Funções primitivas
Table of Contents
- 1. Importações
- 2.
(cons x y)
- 3.
(car x)
- 4.
(cdr x)
- 5.
(copy x)
- 6.
(length x)
- 7.
(depth x)
- 8.
(type x)
- 9.
(intern x)
- 10.
(name x)
- 11.
(get-environment type)
- 12.
(coin)
- 13.
(sys com . args)
- 14.
(format fmt . rest)
- 15.
(err fmt . rest)
- 16.
(warn fmt . rest)
- 17.
(list . rest)
- 18.
(append . rest)
- 19.
(last x)
- 20.
(reverse x)
- 21.
(nthcdr n lst)
- 22.
(nth n lst)
- 23.
(macroexpand-1 x)
- 24. TODO
(macroexpand x)
- 25.
(not x)
- 26.
(gensym)
- 27. Funções numéricas
- 28. TODO Funções de comparação
- 29. Funções aritméticas
- 30. Funções de streams
- 31. Funções de entrada e saída
- 32. Funções de vetores
- 33. Funções customizadas
- 34. Registro em contexto global
Arquivo: axioms/primitives.rs
.
1. Importações
//use std::fs::File; use gc::Gc; use crate::core::{ Maj, MajState }; use super::predicates::{ maj_eq, maj_nilp, maj_consp, maj_errorp, maj_stringp, maj_numberp, maj_vectorp, maj_proper_list_p }; use crate::{ maj_list, maj_destructure_args }; use super::MajRawSym; use num_traits::FromPrimitive; use crate::axioms::utils::{ simplify_frac, simplify_frac_coerce }; use crate::core::types::MajVectorType;
2. (cons x y)
pub fn maj_cons(x: Gc<Maj>, y: Gc<Maj>) -> Gc<Maj> { if maj_errorp(x.clone()).to_bool() { x } else if maj_errorp(y.clone()).to_bool() { y } else { Maj::cons(x, y) } }
3. (car x)
pub fn maj_car(x: Gc<Maj>) -> Gc<Maj> { match &*x.clone() { Maj::Sym(_) => { if maj_nilp(x.clone()).to_bool() { return Maj::nil(); } }, Maj::Cons { car, cdr: _ } => { return car.clone(); }, _ => {} } maj_err(Maj::string("{} is not a cons cell"), maj_list!(x)) }
4. (cdr x)
pub fn maj_cdr(x: Gc<Maj>) -> Gc<Maj> { match &*x.clone() { Maj::Sym(_) => { if maj_nilp(x.clone()).to_bool() { return Maj::nil(); } }, Maj::Cons { car: _, cdr } => { return cdr.clone(); }, _ => {} } maj_err(Maj::string("{} is not a cons cell"), maj_list!(x)) }
5. (copy x)
pub fn maj_copy(x: Gc<Maj>) -> Gc<Maj> { match &*x.clone() { Maj::Cons { car, cdr } => { Maj::cons(car.clone(), cdr.clone()) } _ => maj_err( Maj::string("{} is not a cons cell"), maj_list!(x)) } }
6. (length x)
pub fn maj_length(x: Gc<Maj>) -> Gc<Maj> { if maj_nilp(x.clone()).to_bool() { Maj::integer(0) } else if !maj_consp(x.clone()).to_bool() { maj_err( Maj::string("{} is not a proper list"), maj_list!(x.clone())) } else { let mut itr = x.clone(); let mut length = 0; while maj_consp(itr.clone()).to_bool() { length += 1; itr = maj_cdr(itr); } Maj::integer(length) } }
7. (depth x)
fn maj_depth_helper(x: Gc<Maj>) -> i64 { use std::cmp; if !maj_consp(x.clone()).to_bool() { 0 } else { 1 + cmp::max(maj_depth_helper(maj_car(x.clone())), maj_depth_helper(maj_cdr(x))) } }
pub fn maj_depth(x: Gc<Maj>) -> Gc<Maj> { use crate::axioms::predicates::maj_atomp; if maj_nilp(x.clone()).to_bool() { Maj::integer(0) } else if maj_atomp(x.clone()).to_bool() { maj_err(Maj::string( "{} is an atom"), maj_list!(x)) } else { Maj::integer(maj_depth_helper(x)) } }
8. (type x)
pub fn maj_type(mut state: &mut MajState, x: Gc<Maj>) -> Gc<Maj> { use crate::core::types::MajNumber; Maj::symbol( &mut state, match &*x { Maj::Sym(_) =>"symbol", Maj::Cons { car: _, cdr: _ } => "cons", Maj::Stream(_) => "stream", Maj::Char(_) => "char", Maj::Number(num) => { match num.clone() { MajNumber::Integer(_) => "integer", MajNumber::Float(_) => "float", MajNumber::Fraction(_, _) => "fraction", MajNumber::Complex { real: _, imag: _ } => "complex", } }, Maj::Vector(_) => "vector", }) }
9. (intern x)
pub fn maj_intern(mut state: &mut MajState, x: Gc<Maj>) -> Gc<Maj> { match x.clone().stringify() { Some(string) => { if string == "" { Maj::nil() } else { Maj::symbol(&mut state, &string) } }, None => { maj_err(Maj::string("{} is not a string"), maj_list!(x)) }, } }
10. (name x)
pub fn maj_name(state: &MajState, x: Gc<Maj>) -> Gc<Maj> { use crate::printing::maj_format; if let Maj::Sym(_) = &*x.clone() { Maj::string(&maj_format(&state, x)) } else { maj_err(Maj::string("{} is not a symbol"), maj_list!(x.clone())) } }
11. (get-environment type)
pub fn maj_get_environment( mut state: &mut MajState, type_sym: Gc<Maj>, env: Gc<Maj> ) -> Gc<Maj> { if maj_eq(type_sym.clone(), Maj::symbol(&mut state, "lexical")) .to_bool() { env } else if maj_eq(type_sym.clone(), Maj::symbol(&mut state, "global")) .to_bool() { state.get_global_env() } else { maj_err( Maj::string("Unknown environment type {}"), maj_list!(type_sym)) } }
12. (coin)
pub fn maj_coin() -> Gc<Maj> { use rand::random; if random() { Maj::t() } else { Maj::nil() } }
13. (sys com . args)
pub fn maj_sys(com: Gc<Maj>, args: Gc<Maj>) -> Gc<Maj> { use std::process::Command; if !maj_stringp(com.clone()).to_bool() { return maj_err( Maj::string("{} is not a string"), maj_list!(com)); } let mut comm = Command::new(com.stringify().unwrap()); let mut itr = args.clone(); while !maj_nilp(itr.clone()).to_bool() { if let Maj::Cons { car, cdr } = &*itr.clone() { if !maj_stringp(car.clone()).to_bool() { return maj_err( Maj::string("{} is not a string"), maj_list!(car.clone())); } else { let _ = comm.arg(car.clone() .stringify() .unwrap()); itr = cdr.clone(); } } else {}; } let result = match comm.status() { Ok(res) => res.code(), Err(_) => None, }; match result { Some(code) => Maj::integer(code as i64), None => maj_err( Maj::string("Error executing command {} {}"), maj_list!(com, args)), } }
14. (format fmt . rest)
pub fn maj_format_prim( state: &MajState, fmt: Gc<Maj>, rest: Gc<Maj> ) -> Gc<Maj> { if let Some(rfmt) = fmt.stringify() { let mut buffer = String::new(); let mut expect_closebracket = false; let mut gulp_next = false; let mut curr_arg = rest.clone(); for c in rfmt.chars() { if gulp_next { buffer.push(c); gulp_next = false; } else if expect_closebracket { if c == '}' { use crate::printing::maj_format; expect_closebracket = false; if maj_nilp(curr_arg.clone()).to_bool() { return maj_err( Maj::string("Missing arguments on format"), Maj::nil()); } let cafirst = maj_car(curr_arg.clone()); let mut formatted = if let Maj::Char(c) = &*cafirst.clone() { String::from(format!("{}", c)) } else { maj_format(&state, cafirst) }; let len = formatted.len(); if (len >= 2) && (formatted.chars().nth(0).unwrap() == '"') && (formatted.chars().last().unwrap() == '"') { formatted = String::from(&formatted[1..(len-1)]); } buffer.push_str(formatted.as_str()); curr_arg = maj_cdr(curr_arg); } } else { match c { '{' => expect_closebracket = true, '\\' => gulp_next = true, '}' => { return maj_err( Maj::string( "Unmatched closing curly brace in {}"), maj_list!(fmt)); }, _ => buffer.push(c), } } } if expect_closebracket { return maj_err( Maj::string("Unmatched opening curly brace in {}"), maj_list!(fmt)); } Maj::string(buffer.as_ref()) } else { maj_err(Maj::string("{} is not a string"), maj_list!(fmt)) } }
15. (err fmt . rest)
pub fn maj_err(fmt: Gc<Maj>, rest: Gc<Maj>) -> Gc<Maj> { use crate::maj_dotted_list; if !maj_stringp(fmt.clone()).to_bool() { panic!("Cannot throw error: {} is not a string", fmt); } else if !maj_proper_list_p(rest.clone()).to_bool() { panic!("Cannot throw error: {} is not a proper list", rest); } maj_dotted_list!(Maj::lit(), Maj::error(), fmt, rest) }
16. (warn fmt . rest)
pub fn maj_warn(mut state: &mut MajState, fmt: Gc<Maj>, rest: Gc<Maj>, env: Gc<Maj> ) -> Gc<Maj> { let format = maj_format_prim(&state, fmt, rest); if maj_errorp(format.clone()).to_bool() { format } else { let stderr = Maj::symbol(&mut state, "*stderr*"); let stderr = state.lookup(env, stderr); if maj_errorp(stderr.clone()).to_bool() { stderr } else { maj_write_string( &mut state, format, stderr.clone()); maj_write_char( &mut state, Maj::character('\n'), stderr); Maj::nil() } } }
17. (list . rest)
#[inline] pub fn maj_list(rest: Gc<Maj>) -> Gc<Maj> { rest }
18. (append . rest)
pub fn maj_append(rest: Gc<Maj>) -> Gc<Maj> { use crate::maj_dotted_list; use crate::axioms::predicates::maj_atomp; let car = maj_car(rest.clone()); let cdr = maj_cdr(rest.clone()); let cadr = maj_car(cdr.clone()); let cddr = maj_cdr(cdr.clone()); if maj_nilp(cdr.clone()).to_bool() { return car; } let mut itr = car.clone(); let mut v = Vec::new(); while !maj_nilp(itr.clone()).to_bool() { let cdar = maj_cdr(itr.clone()); if maj_atomp(cdar.clone()).to_bool() && !maj_nilp(cdar.clone()).to_bool() { return maj_err( Maj::string("Cannot append to dotted list"), Maj::nil()); } v.push(maj_car(itr.clone())); itr = cdar; } itr = cadr.clone(); for obj in v.iter().rev() { itr = Maj::cons(obj.clone(), itr.clone()); } maj_append(maj_dotted_list!(itr.clone(), cddr)) }
19. (last x)
pub fn maj_last(x: Gc<Maj>) -> Gc<Maj> { if !maj_consp(x.clone()).to_bool() { return maj_err( Maj::string("{} is not a cons"), maj_list!(x)); } let mut itr = x; loop { let cdr = maj_cdr(itr.clone()); if !maj_consp(cdr.clone()).to_bool() { return itr; } itr = cdr; } }
20. (reverse x)
pub fn maj_reverse(x: Gc<Maj>) -> Gc<Maj> { use crate::axioms::predicates::maj_atomp; if !maj_consp(x.clone()).to_bool() { return maj_err( Maj::string("{} is not a cons"), maj_list!(x)); } let mut itr = x.clone(); let mut newlist = Maj::nil(); while !maj_nilp(itr.clone()).to_bool() { newlist = Maj::cons(maj_car(itr.clone()), newlist); itr = maj_cdr(itr); let is_atom = maj_atomp(itr.clone()).to_bool(); if is_atom && !maj_nilp(itr.clone()).to_bool() { return maj_err( Maj::string("Not a proper list: {}"), maj_list!(x)); } } newlist }
21. (nthcdr n lst)
pub fn maj_nthcdr(n: Gc<Maj>, lst: Gc<Maj>) -> Gc<Maj> { use crate::axioms::predicates::maj_integerp; if maj_nilp(lst.clone()).to_bool() { return Maj::nil(); } if !maj_integerp(n.clone()).to_bool() { return maj_err(Maj::string("{} is not an integer"), maj_list!(n)) } let mut num = n.to_integer().unwrap(); if num < 0 { return maj_err(Maj::string("{} is not a valid index"), maj_list!(n)); } let mut iter = lst.clone(); loop { if !maj_consp(iter.clone()).to_bool() && !maj_nilp(iter.clone()).to_bool() { return maj_err(Maj::string("{} is not a list"), maj_list!(iter)); } if num <= 0 { break; } num -= 1; iter = maj_cdr(iter); } iter }
22. (nth n lst)
pub fn maj_nth(n: Gc<Maj>, lst: Gc<Maj>) -> Gc<Maj> { let cons = maj_nthcdr(n, lst); if maj_errorp(cons.clone()).to_bool() { cons } else { maj_car(cons) } }
23. (macroexpand-1 x)
pub fn maj_macroexpand_1(mut state: &mut MajState, expr: Gc<Maj>, env: Gc<Maj>) -> (Gc<Maj>, bool) { use crate::evaluator::application::expand_macro; if !maj_consp(expr.clone()).to_bool() { return (expr, true); } let mac = maj_car(expr.clone()); let args = maj_cdr(expr.clone()); let mac = state.lookup(env.clone(), mac); expand_macro(&mut state, mac, args, env) }
24. TODO (macroexpand x)
25. (not x)
#[inline] pub fn maj_not(x: Gc<Maj>) -> Gc<Maj> { maj_nilp(x) }
26. (gensym)
#[inline] pub fn maj_gensym(mut state: &mut MajState) -> Gc<Maj> { Maj::gensym(&mut state) }
27. Funções numéricas
27.1. (number-coerce x subtype)
pub fn maj_number_coerce( mut state: &mut MajState, subtype: Gc<Maj>, number: Gc<Maj> ) -> Gc<Maj> { use crate::printing::maj_format; use crate::axioms::predicates::maj_symbolp; if !maj_numberp(number.clone()).to_bool() { return maj_err(Maj::string("{} is not a number"), maj_list!(number)); } if !maj_symbolp(subtype.clone()).to_bool() { return maj_err(Maj::string("{} is not a symbol"), maj_list!(subtype)); } let number_type = maj_type(&mut state, number.clone()); let number_type = number_type.to_raw_sym().unwrap(); let number_type = FromPrimitive::from_u64(number_type) .unwrap(); let coerce_type = subtype.to_raw_sym().unwrap(); let coerce_type = FromPrimitive::from_u64(coerce_type); match number_type { MajRawSym::Integer => match coerce_type { Some(MajRawSym::Integer) => number, Some(MajRawSym::Float) => { Maj::float(number.to_forced_float().unwrap()) }, Some(MajRawSym::Fraction) => { Maj::fraction(number.to_integer().unwrap(), 1) }, Some(MajRawSym::Complex) => { Maj::complex(number.clone(), Maj::float(0.0)) }, _ => maj_err( Maj::string("{} is not a number subtype"), maj_list!(subtype)), }, MajRawSym::Float => match coerce_type { Some(MajRawSym::Integer) => { Maj::integer(number .to_float() .unwrap() .trunc() as i64) }, Some(MajRawSym::Float) => number, Some(MajRawSym::Fraction) => { let mut buffer = maj_format(&state, number); let dot_index = buffer.find('.').unwrap(); let denom_pow = (buffer.len() - dot_index - 1) as u32; let denom = 10_i64.pow(denom_pow); buffer.remove(dot_index); let frac = Maj::fraction(buffer.parse().unwrap(), denom); simplify_frac(frac).unwrap() }, Some(MajRawSym::Complex) => { Maj::complex(number.clone(), Maj::float(0.0)) }, _ => maj_err( Maj::string("{} is not a number subtype"), maj_list!(subtype)), }, MajRawSym::Fraction => match coerce_type { Some(MajRawSym::Integer) => { Maj::integer(number.to_forced_float() .unwrap() .trunc() as i64) }, Some(MajRawSym::Float) => { Maj::float(number.to_forced_float() .unwrap()) }, Some(MajRawSym::Fraction) => number, Some(MajRawSym::Complex) => { Maj::complex(number.clone(), Maj::float(0.0)) }, _ => maj_err( Maj::string("{} is not a number subtype"), maj_list!(subtype)), }, MajRawSym::Complex => match coerce_type { Some(MajRawSym::Integer) | Some(MajRawSym::Float) | Some(MajRawSym::Fraction) => { let realpart = maj_real_part(number); maj_number_coerce(&mut state, subtype, realpart) }, Some(MajRawSym::Complex) => number, _ => maj_err( Maj::string("{} is not a number subtype"), maj_list!(subtype)), }, _ => panic!("Symbol is not a number subtype"), } }
27.2. (real-part x)
pub fn maj_real_part(x: Gc<Maj>) -> Gc<Maj> { use crate::core::types::MajNumber; match &*x.clone() { Maj::Number(num) => { match &num.clone() { MajNumber::Complex { real, imag: _ } => { let real = &*real.clone(); Gc::new(Maj::Number(real.clone())) }, _ => maj_err(Maj::string( "{} is not a complex number"), maj_list!(x)), } }, _ => maj_err(Maj::string("{} is not a number"), maj_list!(x)), } }
27.3. (imag-part x)
pub fn maj_imag_part(x: Gc<Maj>) -> Gc<Maj> { use crate::core::types::MajNumber; match &*x.clone() { Maj::Number(num) => { match &num.clone() { MajNumber::Complex { real: _, imag } => { let imag = &*imag.clone(); Gc::new(Maj::Number(imag.clone())) }, _ => maj_err(Maj::string( "{} is not a complex number"), maj_list!(x)), } }, _ => maj_err(Maj::string("{} is not a number"), maj_list!(x)), } }
27.4. (numer x)
pub fn maj_numer(x: Gc<Maj>) -> Gc<Maj> { if !maj_numberp(x.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(x)) } else { match x.clone().to_fraction() { Some((numer, _)) => Maj::integer(numer), None => maj_err(Maj::string("{} is not a fraction"), maj_list!(x)), } } }
27.5. (denom x)
pub fn maj_denom(x: Gc<Maj>) -> Gc<Maj> { if !maj_numberp(x.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(x)) } else { match x.clone().to_fraction() { Some((_, denom)) => Maj::integer(denom), None => maj_err(Maj::string("{} is not a fraction"), maj_list!(x)), } } }
27.6. (richest-number-type x y)
pub fn maj_richest_number_type( mut state: &mut MajState, x: Gc<Maj>, y: Gc<Maj> ) -> Gc<Maj> { if !maj_numberp(x.clone()).to_bool() { return maj_err(Maj::string("{} is not a number"), maj_list!(x)); } if !maj_numberp(y.clone()).to_bool() { return maj_err(Maj::string("{} is not a number"), maj_list!(y)); } let x_type = maj_type(&mut state, x.clone()); let x_type_sym = x_type.to_raw_sym().unwrap(); let x_type_sym = FromPrimitive::from_u64(x_type_sym).unwrap(); let y_type = maj_type(&mut state, y.clone()); let y_type_sym = y_type.to_raw_sym().unwrap(); let y_type_sym = FromPrimitive::from_u64(y_type_sym).unwrap(); match x_type_sym { MajRawSym::Integer => { match y_type_sym { MajRawSym::Integer | MajRawSym::Float | MajRawSym::Fraction | MajRawSym::Complex => y_type, _ => unimplemented!( "Usage of unknown number subtype"), } }, MajRawSym::Float => { match y_type_sym { MajRawSym::Integer => x_type, MajRawSym::Float | MajRawSym::Fraction | MajRawSym::Complex => y_type, _ => unimplemented!( "Usage of unknown number subtype"), } }, MajRawSym::Fraction => { match y_type_sym { MajRawSym::Integer | MajRawSym::Float | MajRawSym::Fraction => x_type, MajRawSym::Complex => y_type, _ => unimplemented!( "Usage of unknown number subtype"), } }, MajRawSym::Complex => { match y_type_sym { MajRawSym::Integer | MajRawSym::Float | MajRawSym::Fraction | MajRawSym::Complex => x_type, _ => unimplemented!( "Usage of unknown number subtype"), } }, _ => unimplemented!("Usage of unknown number subtype"), } }
27.7. (rich-number-coerce x y)
pub fn maj_rich_number_coerce( mut state: &mut MajState, x: Gc<Maj>, y: Gc<Maj> ) -> Gc<Maj> { let best_type = maj_richest_number_type(&mut state, x.clone(), y.clone()); if maj_errorp(best_type.clone()).to_bool() { return best_type; } maj_list!(maj_number_coerce(&mut state, best_type.clone(), x), maj_number_coerce(&mut state, best_type, y)) }
27.8. (iota n)
#[inline] pub fn maj_iota(n: Gc<Maj>) -> Gc<Maj> { use crate::axioms::predicates::maj_integerp; let common_err = maj_err( Maj::string("iota expects a positive integer number"), Maj::nil()); if !maj_integerp(n.clone()).to_bool() { common_err } else { let mut num = n.to_integer().unwrap(); if num < 0 { common_err } else { let mut list = Maj::nil(); while num > 0 { list = Maj::cons(Maj::integer(num - 1), list); num -= 1; } list } } }
28. TODO Funções de comparação
use crate::axioms::predicates::maj_zerop;
28.1. Funções de ajuda e ferramentas
28.1.1. Ajudante de coerções aritméticas
fn maj_arithm_coercion_helper( mut state: &mut MajState, x: Gc<Maj>, y: Gc<Maj> ) -> Result<(Gc<Maj>, Gc<Maj>, MajRawSym), Gc<Maj>> { if !maj_numberp(x.clone()).to_bool() { return Err(maj_err( Maj::string("{} is not a number"), maj_list!(x))); } if !maj_numberp(y.clone()).to_bool() { return Err(maj_err( Maj::string("{} is not a number"), maj_list!(y))); } // Perform rich coercion let coerced = maj_rich_number_coerce(&mut state, x, y); if maj_errorp(coerced.clone()).to_bool() { return Err(coerced); } let x = maj_car(coerced.clone()); let y = maj_car(maj_cdr(coerced)); let ntype = maj_type(&mut state, x.clone()); Ok((x, y, FromPrimitive::from_u64(ntype.to_raw_sym() .unwrap()) .unwrap())) }
28.1.2. Tipos de despacho de aritmética
#[derive(Debug)] enum MajArithmFnType { Equals, Greater, Lesser, Plus, Minus, Multiply, Divide, }
28.1.3. Ajudante de despacho de aritmética
fn maj_arithm_dispatch( mut state: &mut MajState, env: Gc<Maj>, fntype: MajArithmFnType, x: Gc<Maj>, y: Gc<Maj>, rest: Gc<Maj>, accum: bool ) -> Gc<Maj> { let mut origy = y.clone(); match maj_arithm_coercion_helper(&mut state, x, y.clone()) { Err(e) => e, Ok((x, y, ntype)) => { let result = match fntype { MajArithmFnType::Equals => { maj_arithm_internal_eq( &mut state, env.clone(), x, y, ntype) }, MajArithmFnType::Greater => { maj_arithm_internal_gl( x, y, ntype, true) }, MajArithmFnType::Lesser => { maj_arithm_internal_gl( x, y, ntype, false) }, MajArithmFnType::Plus => { maj_arithm_internal_sum( &mut state, env.clone(), x, y, ntype) }, MajArithmFnType::Minus => { maj_arithm_internal_subtract( &mut state, env.clone(), x, y, ntype) }, MajArithmFnType::Multiply => { maj_arithm_internal_multiply( &mut state, env.clone(), x, y, ntype) }, MajArithmFnType::Divide => { maj_arithm_internal_divide( &mut state, env.clone(), x, y, ntype) }, }; let result = match result { Ok(b) => b, Err(e) => return e, }; if accum { origy = result.clone(); } if !maj_nilp(rest.clone()).to_bool() { maj_arithm_dispatch( &mut state, env, fntype, origy, maj_car(rest.clone()), maj_cdr(rest), accum) } else { result } } } }
28.1.4. Comparação por igualdade
fn maj_arithm_internal_eq( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj>, y: Gc<Maj>, ntype: MajRawSym ) -> Result<Gc<Maj>, Gc<Maj>> { match ntype { MajRawSym::Integer => { let x = x.to_integer().unwrap(); let y = y.to_integer().unwrap(); Ok(if x == y { Maj::t() } else { Maj::nil() }) }, MajRawSym::Fraction => { let (n1, d1) = x.to_fraction().unwrap(); let (n2, d2) = y.to_fraction().unwrap(); Ok(if (n1 == n2) && (d1 == d2) { Maj::t() } else { Maj::nil() }) }, MajRawSym::Complex => { // Comparação recursiva. // Ah... eu posso realmente comparar esses // números dessa forma? let r1 = maj_real_part(x.clone()); let i1 = maj_imag_part(x); let r2 = maj_real_part(y.clone()); let i2 = maj_imag_part(y); let res = maj_arithm_eq(&mut state, env.clone(), r1, r2, Maj::nil()).to_bool() && maj_arithm_eq(&mut state, env.clone(), i1, i2, Maj::nil()).to_bool(); Ok(if res { Maj::t() } else { Maj::nil() }) }, MajRawSym::Float => { let fres = maj_arithm_floateq(&mut state, env.clone(), x, y); if maj_errorp(fres.clone()).to_bool() { return Err(fres); } Ok(fres) }, t => panic!("{:?} is not a number subtype", t), } }
28.1.5. Comparação de maior que / menor que
fn maj_arithm_internal_gl( x: Gc<Maj>, y: Gc<Maj>, ntype: MajRawSym, is_greater: bool ) -> Result<Gc<Maj>, Gc<Maj>> { match ntype { MajRawSym::Integer => { let x = x.to_integer().unwrap(); let y = y.to_integer().unwrap(); let res = if is_greater { x > y } else { x < y }; Ok(if res { Maj::t() } else { Maj::nil() }) }, MajRawSym::Float => { let x = x.to_float().unwrap(); let y = y.to_float().unwrap(); let res = if is_greater { x > y } else { x < y }; Ok(if res { Maj::t() } else { Maj::nil() }) }, MajRawSym::Fraction => { // Use common denominator test let (n1, d1) = x.to_fraction().unwrap(); let (n2, d2) = y.to_fraction().unwrap(); let res = if is_greater { (n1 * d2) > (n2 * d1) } else { (n1 * d2) < (n2 * d1) }; Ok(if res { Maj::t() } else { Maj::nil() }) }, MajRawSym::Complex => Err(maj_err(Maj::string( "The set of complex numbers can't be an ordered field"), Maj::nil())), t => panic!("{:?} is not a number subtype", t), } }
28.2. (= x y . rest)
pub fn maj_arithm_eq( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj>, y: Gc<Maj>, rest: Gc<Maj> ) -> Gc<Maj> { maj_arithm_dispatch(&mut state, env, MajArithmFnType::Equals, x, y, rest, false) }
28.3. (float= x y)
pub fn maj_arithm_floateq( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj>, y: Gc<Maj> ) -> Gc<Maj> { use crate::axioms::predicates::maj_floatp; use core::f64; use float_cmp::approx_eq; if !maj_floatp(x.clone()).to_bool() { return maj_err(Maj::string("{} is not a float number"), maj_list!(x)); } else if !maj_floatp(y.clone()).to_bool() { return maj_err(Maj::string("{} is not a float number"), maj_list!(y)); } let ulps = Maj::symbol(&mut state, "*ulps*"); let ulps = state.lookup(env, ulps); if maj_errorp(ulps.clone()).to_bool() { return ulps; } if let Some(u) = ulps.to_integer() { if u < 0 { maj_err( Maj::string("*ulps* cannot be smaller than 0"), Maj::nil()) } else { let x = x.to_float().unwrap(); let y = y.to_float().unwrap(); if approx_eq!(f64, x, y, ulps = u) { Maj::t() } else { Maj::nil() } } } else { maj_err(Maj::string("*ulps* is not an integer"), Maj::nil()) } }
28.4. (> x y . rest)
pub fn maj_arithm_greater( mut state: &mut MajState, x: Gc<Maj>, y: Gc<Maj>, rest: Gc<Maj> ) -> Gc<Maj> { maj_arithm_dispatch(&mut state, Maj::nil(), MajArithmFnType::Greater, x, y, rest, false) }
28.5. (< x y . rest)
pub fn maj_arithm_lesser( mut state: &mut MajState, x: Gc<Maj>, y: Gc<Maj>, rest: Gc<Maj> ) -> Gc<Maj> { maj_arithm_dispatch(&mut state, Maj::nil(), MajArithmFnType::Lesser, x, y, rest, false) }
28.6. (>= x y . rest)
pub fn maj_arithm_geq( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj>, y: Gc<Maj>, rest: Gc<Maj> ) -> Gc<Maj> { let result = maj_arithm_greater(&mut state, x.clone(), y.clone(), rest.clone()); if maj_errorp(result.clone()).to_bool() { result } else if result.to_bool() { Maj::t() } else { maj_arithm_eq(&mut state, env, x, y, rest) } }
28.7. (<= x y . rest)
pub fn maj_arithm_leq( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj>, y: Gc<Maj>, rest: Gc<Maj> ) -> Gc<Maj> { let result = maj_arithm_lesser(&mut state, x.clone(), y.clone(), rest.clone()); if maj_errorp(result.clone()).to_bool() { result } else if result.to_bool() { Maj::t() } else { maj_arithm_eq(&mut state, env, x, y, rest) } }
29. Funções aritméticas
29.1. Funções de ajuda e ferramentas
29.1.1. Ajudante de soma
fn maj_arithm_internal_sum( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj>, y: Gc<Maj>, ntype: MajRawSym ) -> Result<Gc<Maj>, Gc<Maj>> { match ntype { MajRawSym::Integer => { let x = x.to_integer().unwrap(); let y = y.to_integer().unwrap(); Ok(Maj::integer(x + y)) }, MajRawSym::Float => { let x = x.to_float().unwrap(); let y = y.to_float().unwrap(); Ok(Maj::float(x + y)) }, MajRawSym::Fraction => { let (nx, dx) = x.to_fraction().unwrap(); let (ny, dy) = y.to_fraction().unwrap(); let dr = dx * dy; let nr = (nx * dy) + (ny * dx); simplify_frac_coerce(Maj::fraction(nr, dr)) }, MajRawSym::Complex => { let xr = maj_real_part(x.clone()); let xi = maj_imag_part(x); let yr = maj_real_part(y.clone()); let yi = maj_imag_part(y); let real = maj_arithm_plus( &mut state, env.clone(), maj_list!(xr, yr)); let imag = maj_arithm_plus( &mut state, env, maj_list!(xi, yi)); Ok(Maj::complex(real, imag)) }, t => panic!("{:?} is not a number subtype", t), } }
- Ajudante de conjugado
fn maj_conjugate( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj> ) -> Gc<Maj> { use crate::axioms::predicates::maj_complexp; if !maj_complexp(x.clone()).to_bool() { x } else { let realpart = maj_real_part(x.clone()); let imagpart = maj_imag_part(x); let imagpart = maj_arithm_times( &mut state, env, maj_list!(imagpart, Maj::integer(-1))); if maj_errorp(imagpart.clone()).to_bool() { imagpart } else { Maj::complex(realpart, imagpart) } } }
29.1.2. Ajudante de subtração
fn maj_arithm_internal_subtract( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj>, y: Gc<Maj>, ntype: MajRawSym ) -> Result<Gc<Maj>, Gc<Maj>> { match ntype { MajRawSym::Integer => { let x = x.to_integer().unwrap(); let y = y.to_integer().unwrap(); Ok(Maj::integer(x - y)) }, MajRawSym::Float => { let x = x.to_float().unwrap(); let y = y.to_float().unwrap(); Ok(Maj::float(x - y)) }, MajRawSym::Fraction => { let (nx, dx) = x.to_fraction().unwrap(); let (ny, dy) = y.to_fraction().unwrap(); let dr = dx * dy; let nr = (nx * dy) - (ny * dx); simplify_frac_coerce(Maj::fraction(nr, dr)) }, MajRawSym::Complex => { let xr = maj_real_part(x.clone()); let xi = maj_imag_part(x); let yr = maj_real_part(y.clone()); let yi = maj_imag_part(y); let real = maj_arithm_minus( &mut state, env.clone(), maj_list!(xr, yr)); let imag = maj_arithm_minus( &mut state, env, maj_list!(xi, yi)); Ok(Maj::complex(real, imag)) }, t => panic!("{:?} is not a number subtype", t), } }
29.1.3. Ajudante de multiplicação
fn maj_arithm_internal_multiply( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj>, y: Gc<Maj>, ntype: MajRawSym ) -> Result<Gc<Maj>, Gc<Maj>> { match ntype { MajRawSym::Integer => { let x = x.to_integer().unwrap(); let y = y.to_integer().unwrap(); Ok(Maj::integer(x * y)) }, MajRawSym::Float => { let x = x.to_float().unwrap(); let y = y.to_float().unwrap(); Ok(Maj::float(x * y)) }, MajRawSym::Fraction => { let (nx, dx) = x.to_fraction().unwrap(); let (ny, dy) = y.to_fraction().unwrap(); let nr = nx * ny; let dr = dx * dy; simplify_frac_coerce(Maj::fraction(nr, dr)) }, MajRawSym::Complex => { Ok(maj_arithm_internal_complex_mult( &mut state, env, x, y)) }, t => panic!("{:?} is not a number subtype", t), } }
fn maj_arithm_internal_complex_mult( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj>, y: Gc<Maj> ) -> Gc<Maj> { let xr = maj_real_part(x.clone()); let xi = maj_imag_part(x); let yr = maj_real_part(y.clone()); let yi = maj_imag_part(y); let firsts = maj_arithm_times( &mut state, env.clone(), maj_list!(xr.clone(), yr.clone())); let outers = Maj::complex( Maj::integer(0), maj_arithm_times( &mut state, env.clone(), maj_list!(xr.clone(), yi.clone()))); let inners = Maj::complex( Maj::integer(0), maj_arithm_times( &mut state, env.clone(), maj_list!(xi.clone(), yr.clone()))); let lasts = maj_arithm_times( &mut state, env.clone(), maj_list!(xi, yi)); let lasts = maj_negate(&mut state, env.clone(), lasts); maj_arithm_plus( &mut state, env, maj_list!(firsts, outers, inners, lasts)) }
- Ajudante de dedução de sinal
fn maj_signum( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj> ) -> Gc<Maj> { if maj_zerop(&mut state, env, x.clone()).to_bool() { x } else if maj_arithm_lesser( &mut state, x.clone(), Maj::integer(0), Maj::nil()).to_bool() { Maj::integer(-1) } else { Maj::integer(1) } }
29.1.4. Ajudante de divisão
fn maj_arithm_internal_divide( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj>, y: Gc<Maj>, ntype: MajRawSym ) -> Result<Gc<Maj>, Gc<Maj>> { match ntype { MajRawSym::Integer => { let x = x.to_integer().unwrap(); let y = y.to_integer().unwrap(); if y == 0 { Err(maj_err(Maj::string("Division by zero"), Maj::nil())) } else { Ok(if x % y == 0 { Maj::integer(x / y) } else { simplify_frac_coerce(Maj::fraction(x, y)).unwrap() }) } }, MajRawSym::Float => { if maj_zerop(&mut state, env, y.clone()).to_bool() { Err(maj_err(Maj::string("Division by zero"), Maj::nil())) } else { let x = x.to_float().unwrap(); let y = y.to_float().unwrap(); Ok(Maj::float(x / y)) } }, MajRawSym::Fraction => { let (nx, dx) = x.to_fraction().unwrap(); let (ny, dy) = y.to_fraction().unwrap(); let nr = nx * dy; let dr = dx * ny; // Division by zero verified by this function simplify_frac_coerce(Maj::fraction(nr, dr)) }, MajRawSym::Complex => { return maj_arithm_internal_complex_div( &mut state, env, x, y); }, t => panic!("{:?} is not a number subtype", t), } }
fn maj_arithm_internal_complex_div( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj>, y: Gc<Maj> ) -> Result<Gc<Maj>, Gc<Maj>> { let yconj = maj_arithm_plus( &mut state, env.clone(), maj_list!(y.clone())); let dividend = maj_arithm_times( &mut state, env.clone(), maj_list!(x, yconj.clone())); let divisor = maj_arithm_times( &mut state, env.clone(), maj_list!(y, yconj.clone())); let divisor = maj_real_part(divisor); if maj_zerop(&mut state, env.clone(), divisor.clone() ).to_bool() { return Err(maj_err(Maj::string("Division by zero"), Maj::nil())); } let dividend_r = maj_real_part(dividend.clone()); let dividend_i = maj_imag_part(dividend); let realpart = maj_arithm_divide( &mut state, env.clone(), maj_list!(dividend_r, divisor.clone())); let imagpart = maj_arithm_divide( &mut state, env.clone(), maj_list!(dividend_i, divisor.clone())); Ok(Maj::complex(realpart, imagpart)) }
- Ajudante de recíproco
fn maj_reciprocal( mut state: &mut MajState, env: Gc<Maj>, x: Gc<Maj> ) -> Gc<Maj> { if maj_zerop(&mut state, env.clone(), x.clone()).to_bool() { maj_err(Maj::string("Division by zero"), Maj::nil()) } else { maj_arithm_divide( &mut state, env, maj_list!(Maj::fraction(1, 1), x.clone())) } }
29.2. (+ . rest)
pub fn maj_arithm_plus( mut state: &mut MajState, env: Gc<Maj>, rest: Gc<Maj> ) -> Gc<Maj> { let len = maj_length(rest.clone()); if maj_errorp(len.clone()).to_bool() { return len; } match len.to_integer().unwrap() { 0 => Maj::integer(1), 1 => { maj_destructure_args!(rest, x); if !maj_numberp(x.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(x)) } else { maj_conjugate(&mut state, env, x) } }, _ => { maj_destructure_args!(rest, x, r1, y, rest); if !maj_numberp(x.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(x)) } else if !maj_numberp(y.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(y)) } else { maj_arithm_dispatch( &mut state, Maj::nil(), MajArithmFnType::Plus, x, y, rest, true) } }, } }
29.3. (- . rest)
pub fn maj_arithm_minus( mut state: &mut MajState, env: Gc<Maj>, rest: Gc<Maj> ) -> Gc<Maj> { let len = maj_length(rest.clone()); if maj_errorp(len.clone()).to_bool() { return len; } match len.to_integer().unwrap() { 0 => Maj::integer(0), 1 => { maj_destructure_args!(rest, x); if !maj_numberp(x.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(x)) } else { maj_negate(&mut state, env, x) } }, _ => { maj_destructure_args!(rest, x, r1, y, rest); if !maj_numberp(x.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(x)) } else if !maj_numberp(y.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(y)) } else { maj_arithm_dispatch( &mut state, Maj::nil(), MajArithmFnType::Minus, x, y, rest, true) } }, } }
29.4. (* . rest)
pub fn maj_arithm_times( mut state: &mut MajState, env: Gc<Maj>, rest: Gc<Maj> ) -> Gc<Maj> { let len = maj_length(rest.clone()); if maj_errorp(len.clone()).to_bool() { return len; } match len.to_integer().unwrap() { 0 => Maj::integer(1), 1 => { maj_destructure_args!(rest, x); if !maj_numberp(x.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(x)) } else { maj_signum(&mut state, env, x) } }, _ => { maj_destructure_args!(rest, x, r1, y, rest); if !maj_numberp(x.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(x)) } else if !maj_numberp(y.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(y)) } else { maj_arithm_dispatch( &mut state, Maj::nil(), MajArithmFnType::Multiply, x, y, rest, true) } }, } }
29.5. (/ . rest)
pub fn maj_arithm_divide( mut state: &mut MajState, env: Gc<Maj>, rest: Gc<Maj> ) -> Gc<Maj> { let len = maj_length(rest.clone()); if maj_errorp(len.clone()).to_bool() { return len; } match len.to_integer().unwrap() { 0 => Maj::integer(1), 1 => { maj_destructure_args!(rest, x); if !maj_numberp(x.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(x)) } else { maj_reciprocal(&mut state, env, x) } }, _ => { maj_destructure_args!(rest, x, r1, y, rest); if !maj_numberp(x.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(x)) } else if !maj_numberp(y.clone()).to_bool() { maj_err(Maj::string("{} is not a number"), maj_list!(y)) } else { maj_arithm_dispatch( &mut state, Maj::nil(), MajArithmFnType::Divide, x, y, rest, true) } }, } }
30. Funções de streams
30.1. Funções auxiliares
use crate::core::types::{ MajStreamType, MajStreamDirection };
30.1.1. Desempacotamento de um File
fn get_raw_stream( mut state: &mut MajState, stream: Gc<Maj>, expected_dir: MajStreamDirection ) -> Result<&std::fs::File, Gc<Maj>> { use std::io::Seek; if let Maj::Stream(mstream) = &*stream.clone() { if mstream.is_internal() { panic!("Never try to use *stdin* or *stdout* as ordinary streams!"); } if maj_nilp(state.stat_stream(mstream.handle)).to_bool() { Err(maj_err( Maj::string("The stream {} is closed"), maj_list!(stream))) } else if mstream.direction == expected_dir { let eof_sym = Maj::symbol(&mut state, "eof"); let file = state.borrow_stream(mstream.handle); let mut file = file.unwrap(); if expected_dir == MajStreamDirection::In { // Check if eof. // If fails, position is unspecified and should // error out anyway. So we use unwrap. let length = file.stream_len().unwrap(); let pos = file.stream_position().unwrap(); if pos >= length { return Err(eof_sym) } } Ok(file) } else { Err(maj_err( Maj::string("{} is not an {} stream"), maj_list!( stream, Maj::string( if expected_dir == MajStreamDirection::In { "input" } else { "output" })))) } } else { Err(maj_err( Maj::string("{} is not a stream"), maj_list!(stream))) } }
30.1.2. Testes de stream padrão
fn stdstreamp(x: Gc<Maj>) -> bool { if let Maj::Stream(mstream) = &*x.clone() { mstream.is_internal() } else { false } }
fn stdstreamdirp(x: Gc<Maj>, dir: MajStreamDirection) -> bool { if let Maj::Stream(mstream) = &*x.clone() { if !mstream.is_internal() { panic!("Not a standard stream being tested"); } dir == mstream.direction } else { false } }
fn stdstreamtype(x: Gc<Maj>) -> MajStreamType { if let Maj::Stream(mstream) = &*x.clone() { if !mstream.is_internal() { panic!("Not a standard stream being tested"); } mstream.stype.clone() } else { panic!("Not a standard stream being tested"); } }
30.2. (open-stream dir path)
pub fn maj_open_stream( mut state: &mut MajState, dir: Gc<Maj>, path: Gc<Maj> ) -> Gc<Maj> { let path_opt = path.stringify(); if path_opt.is_none() { return maj_err( Maj::string("{} is not a string"), maj_list!(path)); } let direction = if maj_eq(Maj::symbol(&mut state, "in"), dir.clone()).to_bool() { MajStreamDirection::In } else if maj_eq(Maj::symbol(&mut state, "out"), dir.clone()).to_bool() { MajStreamDirection::Out } else { return maj_err( Maj::string("{} should be one of symbols 'in or 'out"), maj_list!(dir)); }; let stream = state.make_stream(&path_opt.unwrap(), direction); match stream { Some(obj) => obj, None => maj_err( Maj::string("Cannot open stream to path {}"), maj_list!(path)), } }
30.3. (close-stream x)
pub fn maj_close_stream( state: &mut MajState, x: Gc<Maj> ) -> Gc<Maj> { state.close_stream(x) }
30.4. (stat x)
pub fn maj_stat(mut state: &mut MajState, x: Gc<Maj>) -> Gc<Maj> { if let Maj::Stream(mstream) = &*x.clone() { let index = mstream.handle; let result = state.stat_stream(index); if maj_errorp(result.clone()).to_bool() { result } else if maj_nilp(result.clone()).to_bool() { Maj::symbol(&mut state, "closed") } else { Maj::symbol(&mut state, "open") } } else { maj_err( Maj::string("Not a stream: {}"), maj_list!(x)) } }
30.5. (read-char stream)
pub fn maj_read_char(mut state: &mut MajState, stream: Gc<Maj> ) -> Gc<Maj> { use std::io::Read; let mut buffer = [0; 1]; if stdstreamp(stream.clone()) { if stdstreamdirp(stream.clone(), MajStreamDirection::In) { let peekopt = state.pop_stdin_peeked(); match peekopt { Some(c) => { return Maj::character(c); }, None => { use std::io; match io::stdin().read(&mut buffer) { Ok(_) => { return Maj::character(buffer[0] as char); }, Err(_) => { return maj_err( Maj::string( "Could not read from stream *stdin*"), Maj::nil()); } } }, } } else { return maj_err( Maj::string("{} is not an input stream"), maj_list!(stream)); } } match get_raw_stream(&mut state, stream.clone(), MajStreamDirection::In) { Ok(mut file) => { match file.read(&mut buffer) { Ok(_) => { Maj::character(buffer[0] as char) }, Err(_) => { maj_err( Maj::string( "Could not read from stream {}"), maj_list!(stream)) } } }, Err(expr) => expr, } }
30.6. (peek-char stream)
pub fn maj_peek_char(mut state: &mut MajState, stream: Gc<Maj> ) -> Gc<Maj> { use std::io::{ Read, Seek, SeekFrom }; let mut buffer = [0; 1]; if stdstreamp(stream.clone()) { if stdstreamdirp(stream.clone(), MajStreamDirection::In) { let peekopt = state.pop_stdin_peeked(); match peekopt { Some(c) => { state.push_stdin_peeked(c); return Maj::character(c); }, None => { use std::io; match io::stdin().read(&mut buffer) { Ok(_) => { state.push_stdin_peeked(buffer[0] as char); return Maj::character(buffer[0] as char); }, Err(_) => { return maj_err( Maj::string( "Could not read from stream *stdin*"), Maj::nil()); } } }, } } else { return maj_err( Maj::string("{} is not an input stream"), maj_list!(stream)); } } match get_raw_stream(&mut state, stream.clone(), MajStreamDirection::In) { Ok(mut file) => { match file.read(&mut buffer) { Ok(_) => { // Since a character was read, // seek back to a point before it. // If unable, this should fail anyway file.seek(SeekFrom::Current(-1)) .unwrap(); Maj::character(buffer[0] as char) }, Err(_) => { maj_err( Maj::string( "Could not read from stream {}"), maj_list!(stream)) } } }, Err(expr) => expr, } }
30.7. (write-char c stream)
pub fn maj_write_char(mut state: &mut MajState, c: Gc<Maj>, stream: Gc<Maj> ) -> Gc<Maj> { use std::io::Write; use crate::axioms::predicates::maj_charp; if !maj_charp(c.clone()).to_bool() { return maj_err( Maj::string("{} is not a character"), maj_list!(c)); } let c = c.to_char().unwrap(); if stdstreamp(stream.clone()) { if stdstreamdirp(stream.clone(), MajStreamDirection::Out) { match stdstreamtype(stream) { MajStreamType::Stdout => print!("{}", c), MajStreamType::Stderr => eprint!("{}", c), _ => panic!("write char to stream of wrong type"), }; return Maj::nil(); } else { return maj_err( Maj::string("{} is not an output stream"), maj_list!(stream)); } } match get_raw_stream(&mut state, stream.clone(), MajStreamDirection::Out) { Ok(mut file) => { match write!(file, "{}", c) { Ok(_) => { let _ = file.flush(); Maj::nil() }, Err(_) => { maj_err( Maj::string( "Could not write to stream {}"), maj_list!(stream)) } } }, Err(expr) => expr, } }
30.8. (write-string str stream)
pub fn maj_write_string(mut state: &mut MajState, strn: Gc<Maj>, stream: Gc<Maj> ) -> Gc<Maj> { use std::io::Write; if !maj_stringp(strn.clone()).to_bool() { return maj_err( Maj::string("{} is not a string"), maj_list!(strn)); } let strn = strn.stringify().unwrap(); if stdstreamp(stream.clone()) { if stdstreamdirp(stream.clone(), MajStreamDirection::Out) { match stdstreamtype(stream) { MajStreamType::Stdout => print!("{}", strn), MajStreamType::Stderr => eprint!("{}", strn), _ => panic!("write string to stream of wrong type"), }; return Maj::nil(); } else { return maj_err( Maj::string("{} is not an output stream"), maj_list!(stream)); } } match get_raw_stream(&mut state, stream.clone(), MajStreamDirection::Out) { Ok(mut file) => { match write!(file, "{}", strn) { Ok(_) => { let _ = file.flush(); Maj::nil() }, Err(_) => { maj_err( Maj::string( "Could not write to stream {}"), maj_list!(stream)) } } }, Err(expr) => expr, } }
30.9. (write x stream)
pub fn maj_write(mut state: &mut MajState, x: Gc<Maj>, stream: Gc<Maj> ) -> Gc<Maj> { use crate::printing::maj_format; let string = Maj::string(&maj_format(&state, x)); maj_write_string(&mut state, string, stream) }
30.10. TODO (read stream)
31. Funções de entrada e saída
31.1. (terpri)
pub fn maj_terpri(mut state: &mut MajState, env: Gc<Maj>) -> Gc<Maj> { // Lookup dynamically bound stdout let stdout = Maj::symbol(&mut state, "*stdout*"); let stdout = state.lookup(env.clone(), stdout); if maj_errorp(stdout.clone()).to_bool() { return stdout; } maj_write_char(&mut state, Maj::character('\n'), stdout) }
31.2. (display x)
pub fn maj_display(mut state: &mut MajState, x: Gc<Maj>, env: Gc<Maj> ) -> Gc<Maj> { // Lookup dynamically bound stdout let stdout = Maj::symbol(&mut state, "*stdout*"); let stdout = state.lookup(env.clone(), stdout); if maj_errorp(stdout.clone()).to_bool() { return stdout; } maj_write(&mut state, x, stdout) }
31.3. TODO (pretty-display x)
pub fn maj_pretty_display(mut state: &mut MajState, x: Gc<Maj>, env: Gc<Maj> ) -> Gc<Maj> { use crate::printing::maj_pretty_format; // Lookup dynamically bound stdout let stdout = Maj::symbol(&mut state, "*stdout*"); let stdout = state.lookup(env.clone(), stdout); if maj_errorp(stdout.clone()).to_bool() { return stdout; } let string = maj_pretty_format(&state, x); let string = Maj::string(&string); maj_write_string(&mut state, string, stdout) }
31.4. (print fmt . args)
pub fn maj_print( mut state: &mut MajState, fmt: Gc<Maj>, rest: Gc<Maj>, env: Gc<Maj> ) -> Gc<Maj> { // Lookup dynamically bound stdout let stdout = Maj::symbol(&mut state, "*stdout*"); let stdout = state.lookup(env.clone(), stdout); if maj_errorp(stdout.clone()).to_bool() { return stdout; } let formatted = maj_format_prim(&state, fmt, rest); if maj_errorp(formatted.clone()).to_bool() { formatted } else { maj_write_string(&mut state, formatted, stdout.clone()); maj_write_char(&mut state, Maj::character('\n'), stdout) } }
31.5. TODO (load path)
pub fn maj_load( mut state: &mut MajState, env: Gc<Maj>, path: Gc<Maj> ) -> Gc<Maj> { use crate::reader::parser::maj_parse; use crate::reader::tokenizer::maj_tokenize_file; use crate::evaluator::maj_eval; match path.clone().stringify() { Some(pathstr) => { let mut buffer = String::new(); match maj_tokenize_file(&pathstr, &mut buffer) { Ok(tokens) => { match maj_parse(&mut state, tokens.clone()) { Ok(expressions) => { // TODO: Iterate over forms and yield errors // depending on them let results = maj_eval(&mut state, Maj::cons( Maj::do_sym(), expressions), env); if maj_errorp(results.clone()).to_bool() { maj_err( Maj::string( "On evaluation of file {}: {}"), maj_list!(path, results)) } else { results } }, Err(msg) => { maj_err( Maj::string("While parsing file {}: {}"), maj_list!(path, Maj::string(msg))) }, } }, Err((line, msg)) => { if line != 0 { maj_err( Maj::string("While reading file {}:{}: {}"), maj_list!(path, Maj::integer(line as i64), Maj::string(msg))) } else { maj_err( Maj::string("While reading file {}: {}"), maj_list!(path, Maj::string(msg))) } }, } }, None => maj_err(Maj::string("{} is not a string"), maj_list!(path)), } }
32. Funções de vetores
32.1. (vec-type vec)
pub fn maj_vec_type(mut state: &mut MajState, vec: Gc<Maj>) -> Gc<Maj> { use crate::core::types::MajVector; if !maj_vectorp(vec.clone()).to_bool() { return maj_err( Maj::string("{} is not a vector"), maj_list!(vec)); } if let Maj::Vector(v) = &*vec { return Maj::symbol(&mut state, match v { MajVector::Integer(_) => "integer", MajVector::Float(_) => "float", MajVector::Char(_) => "char", MajVector::Any(_) => "any", }); } panic!("vec-type: Unknown vector type"); }
32.2. (vec-push x vec)
pub fn maj_vec_push(mut state: &mut MajState, x: Gc<Maj>, vec: Gc<Maj>) -> Gc<Maj> { let pos = maj_vec_length(vec.clone()); if maj_errorp(pos.clone()).to_bool() { return pos; } maj_vec_insert(&mut state, pos, x, vec) }
32.3. (vec-insert pos x vec)
pub fn maj_vec_insert(mut state: &mut MajState, pos: Gc<Maj>, x: Gc<Maj>, vec: Gc<Maj>) -> Gc<Maj> { use crate::core::types::MajVector; if !maj_vectorp(vec.clone()).to_bool() { return maj_err( Maj::string("{} is not a vector"), maj_list!(vec)); } let xtype = maj_type(&mut state, x.clone()); let vectype = maj_vec_type(&mut state, vec.clone()); let any = Maj::symbol(&mut state, "any"); let index = match pos.clone().to_integer() { Some(x) => { if x < 0 { return maj_err( Maj::string( "Index {} is out of bounds in {}"), maj_list!(pos, vec)); } x as usize }, None => { return maj_err( Maj::string("{} is not an integer"), maj_list!(pos)); }, }; if !maj_eq(vectype.clone(), any).to_bool() && !maj_eq(xtype.clone(), vectype.clone()).to_bool() { return maj_err( Maj::string( "{} has type {}, which is incompatible with insertion on vector of type {}"), maj_list!(x, xtype, vectype)); } if let Maj::Vector(v) = &*vec.clone() { match v { MajVector::Integer(v) => { let val = x.to_integer().unwrap(); let len = v.borrow().len(); if index > len { maj_err( Maj::string( "Index {} is out of bounds in {}"), maj_list!(pos, vec)) } else { v.borrow_mut().insert(index, val); vec } }, MajVector::Float(v) => { let val = x.to_float().unwrap(); let len = v.borrow().len(); if index > len { maj_err( Maj::string( "Index {} is out of bounds in {}"), maj_list!(pos, vec)) } else { v.borrow_mut().insert(index, val); vec } }, MajVector::Char(s) => { let val = x.to_char().unwrap(); let len = s.borrow().chars().count(); if index > len { maj_err( Maj::string( "Index {} is out of bounds in {}"), maj_list!(pos, vec)) } else { s.borrow_mut().insert(index, val); vec } }, MajVector::Any(v) => { let len = v.borrow().len(); if index > len { maj_err( Maj::string( "Index {} is out of bounds in {}"), maj_list!(pos, vec)) } else { v.borrow_mut().insert(index, x.clone()); vec } } } } else { panic!("vec-insert: Not a vector"); } }
32.4. (vec-coerce vec type)
fn sym_to_vectype(mut state: &mut MajState, vtype: Gc<Maj>) -> MajVectorType { if maj_eq(vtype.clone(), Maj::symbol(&mut state, "integer")).to_bool() { MajVectorType::Integer } else if maj_eq( vtype.clone(), Maj::symbol(&mut state, "float")).to_bool() { MajVectorType::Float } else if maj_eq( vtype.clone(), Maj::symbol(&mut state, "char")).to_bool() { MajVectorType::Char } else { MajVectorType::Any } }
pub fn maj_vec_coerce(mut state: &mut MajState, vtype: Gc<Maj>, vec: Gc<Maj>) -> Gc<Maj> { use crate::core::types::MajVector; if !maj_vectorp(vec.clone()).to_bool() { return maj_err( Maj::string("{} is not a vector"), maj_list!(vec)); } let intended_type = sym_to_vectype(&mut state, vtype.clone()); let newvec = Maj::vector(intended_type); let is_any_intended = maj_eq(vtype.clone(), Maj::symbol(&mut state, "any")) .to_bool(); if let Maj::Vector(v) = &*vec { match v { MajVector::Integer(v) => { for n in v.borrow().iter() { let num = Maj::integer(*n); if !is_any_intended { let num = maj_number_coerce( &mut state, vtype.clone(), num.clone()); if maj_errorp(num.clone()).to_bool() { return num; } } let result = maj_vec_push(&mut state, num.clone(), newvec.clone()); if maj_errorp(result.clone()).to_bool() { return result; } } }, MajVector::Float(v) => { for n in v.borrow().iter() { let num = Maj::float(*n); if !is_any_intended { let num = maj_number_coerce( &mut state, vtype.clone(), num.clone()); if maj_errorp(num.clone()).to_bool() { return num; } } let result = maj_vec_push(&mut state, num.clone(), newvec.clone()); if maj_errorp(result.clone()).to_bool() { return result; } } }, MajVector::Char(s) => { for c in s.borrow().chars() { let result = maj_vec_push(&mut state, Maj::character(c), newvec.clone()); if maj_errorp(result.clone()).to_bool() { return result; } } }, MajVector::Any(v) => { for elt in v.borrow().iter() { let result = maj_vec_push(&mut state, elt.clone(), newvec.clone()); if maj_errorp(result.clone()).to_bool() { return result; } } } } } else { panic!("vec-coerce: Not a vector"); } newvec }
32.5. (vector . rest)
fn vectype_compatible(mut state: &mut MajState, vtype: MajVectorType, xtype: Gc<Maj>) -> bool { match vtype { MajVectorType::Any => true, MajVectorType::Integer => maj_eq(xtype, Maj::symbol(&mut state, "integer")) .to_bool(), MajVectorType::Float => maj_eq(xtype, Maj::symbol(&mut state, "float")) .to_bool(), MajVectorType::Char => maj_eq(xtype, Maj::symbol(&mut state, "char")) .to_bool(), } }
fn best_vectype(mut state: &mut MajState, xtype: Gc<Maj>) -> MajVectorType { let integer = Maj::symbol(&mut state, "integer"); let float = Maj::symbol(&mut state, "float"); let charsym = Maj::symbol(&mut state, "char"); let sym = if maj_eq(xtype.clone(), integer).to_bool() || maj_eq(xtype.clone(), float).to_bool() || maj_eq(xtype.clone(), charsym).to_bool() { xtype } else { Maj::symbol(&mut state, "any") }; sym_to_vectype(&mut state, sym) }
pub fn maj_vector(mut state: &mut MajState, rest: Gc<Maj>) -> Gc<Maj> { if maj_nilp(rest.clone()).to_bool() { Maj::vector(MajVectorType::Any) } else { let mut iter = rest.clone(); let first = maj_car(iter.clone()); let fsttype = maj_type(&mut state, first); let mut vector = Maj::vector( best_vectype(&mut state, fsttype)); while !maj_nilp(iter.clone()).to_bool() { let first = maj_car(iter.clone()); let fsttype = maj_type(&mut state, first.clone()); let vtype = maj_vec_type(&mut state, vector.clone()); let vtype = sym_to_vectype(&mut state, vtype); if !vectype_compatible( &mut state, vtype, fsttype) { let any = Maj::symbol(&mut state, "any"); vector = maj_vec_coerce( &mut state, any, vector); if maj_errorp(vector.clone()).to_bool() { return vector; } } let res = maj_vec_push(&mut state, first, vector.clone()); if maj_errorp(res.clone()).to_bool() { return res; } iter = maj_cdr(iter); } vector } }
32.6. (vec-length vec)
pub fn maj_vec_length(vec: Gc<Maj>) -> Gc<Maj> { use crate::core::types::MajVector; if let Maj::Vector(v) = &*vec.clone() { Maj::integer( match v { MajVector::Integer(v) => v.borrow().len(), MajVector::Float(v) => v.borrow().len(), MajVector::Char(s) => s.borrow().chars().count(), MajVector::Any(v) => v.borrow().len(), } as i64) } else { maj_err( Maj::string("{} is not a vector"), maj_list!(vec)) } }
32.7. (vec-pop vec)
pub fn maj_vec_pop(vec: Gc<Maj>) -> Gc<Maj> { use crate::core::types::MajVector; if let Maj::Vector(vv) = &*vec.clone() { match vv { MajVector::Integer(v) => { match v.borrow_mut().pop() { Some(val) => Maj::integer(val), None => Maj::nil(), } }, MajVector::Float(v) => { match v.borrow_mut().pop() { Some(val) => Maj::float(val), None => Maj::nil(), } }, MajVector::Char(s) => { match s.borrow_mut().pop() { Some(val) => Maj::character(val), None => Maj::nil(), } }, MajVector::Any(v) => { match v.borrow_mut().pop() { Some(val) => val, None => Maj::nil(), } } } } else { maj_err( Maj::string("{} is not a vector"), maj_list!(vec)) } }
32.8. (vec-deq vec)
pub fn maj_vec_deq(vec: Gc<Maj>) -> Gc<Maj> { use crate::core::types::MajVector; if let Maj::Vector(vv) = &*vec.clone() { match vv { MajVector::Integer(v) => { if v.borrow().is_empty() { Maj::nil() } else { Maj::integer( v.borrow_mut().remove(0)) } }, MajVector::Float(v) => { if v.borrow().is_empty() { Maj::nil() } else { Maj::float( v.borrow_mut().remove(0)) } }, MajVector::Char(s) => { if s.borrow().is_empty() { Maj::nil() } else { Maj::character( s.borrow_mut().remove(0)) } }, MajVector::Any(v) => { if v.borrow().is_empty() { Maj::nil() } else { v.borrow_mut().remove(0) } } } } else { maj_err( Maj::string("{} is not a vector"), maj_list!(vec)) } }
32.9. (vec-at x vec)
pub fn maj_vec_at(x: Gc<Maj>, vec: Gc<Maj>) -> Gc<Maj> { use crate::core::types::MajVector; use crate::axioms::predicates::maj_integerp; if !maj_integerp(x.clone()).to_bool() { return maj_err( Maj::string("{} is not an integer"), maj_list!(x)); } let index = x.to_integer().unwrap() as usize; if let Maj::Vector(vv) = &*vec.clone() { match vv { MajVector::Integer(v) => { match v.borrow().get(index) { Some(val) => Maj::integer(*val), None => maj_err( Maj::string("Index {} is out of bounds in {}"), maj_list!(x.clone(), vec)), } }, MajVector::Float(v) => { match v.borrow().get(index) { Some(val) => Maj::float(*val), None => maj_err( Maj::string("Index {} is out of bounds in {}"), maj_list!(x.clone(), vec)), } }, MajVector::Char(s) => { match s.borrow().chars().nth(index) { Some(val) => Maj::character(val), None => maj_err( Maj::string("Index {} is out of bounds in {}"), maj_list!(x.clone(), vec)), } }, MajVector::Any(v) => { match v.borrow().get(index) { Some(val) => val.clone(), None => maj_err( Maj::string("Index {} is out of bounds in {}"), maj_list!(x.clone(), vec)), } } } } else { maj_err( Maj::string("{} is not a vector"), maj_list!(vec)) } }
32.10. (vec-set pos x vec)
fn replace_string_char(strn: &mut String, index: usize, rep: char) { let mut vec = strn.chars().collect::<Vec<_>>(); vec[index] = rep; *strn = vec.iter().collect::<String>(); }
pub fn maj_vec_set( pos: Gc<Maj>, x: Gc<Maj>, vec: Gc<Maj> ) -> Gc<Maj> { use crate::core::types::MajVector; use crate::axioms::predicates::{ maj_integerp, maj_floatp, maj_charp }; let index = match pos.clone().to_integer() { Some(x) => { if x < 0 { return maj_err( Maj::string( "Index {} is out of bounds in {}"), maj_list!(pos, vec)); } x as usize }, None => { return maj_err( Maj::string("{} is not an integer"), maj_list!(pos)); }, }; if let Maj::Vector(vv) = &*vec.clone() { match vv { MajVector::Integer(v) => { if !maj_integerp(x.clone()).to_bool() { return maj_err( Maj::string( "{} is not type-compatible with vector {}"), maj_list!(x.clone(), vec.clone())); } let x = x.to_integer().unwrap(); let len = v.borrow().len(); if index >= len { maj_err( Maj::string("Index {} is out of bounds in {}"), maj_list!(pos, vec)) } else { v.borrow_mut()[index] = x; vec } }, MajVector::Float(v) => { if!maj_floatp(x.clone()).to_bool() { return maj_err( Maj::string( "{} is not type-compatible with vector {}"), maj_list!(x.clone(), vec.clone())); } let x = x.to_float().unwrap(); let len = v.borrow().len(); if index >= len { maj_err( Maj::string("Index {} is out of bounds in {}"), maj_list!(pos, vec)) } else { v.borrow_mut()[index] = x; vec } }, MajVector::Char(s) => { if!maj_charp(x.clone()).to_bool() { maj_err( Maj::string( "{} is not type-compatible with vector {}"), maj_list!(x.clone(), vec.clone())); } let c = x.clone().to_char().unwrap(); let len = s.borrow().len(); if index >= len { maj_err( Maj::string("Index {} is out of bounds in {}"), maj_list!(pos, vec)) } else { replace_string_char(&mut s.borrow_mut(), index, c); vec } }, MajVector::Any(v) => { let len = v.borrow().len(); if index >= len { return maj_err( Maj::string("Index {} is out of bounds in {}"), maj_list!(pos, vec)) } else { v.borrow_mut()[index] = x.clone(); vec } }, } } else { maj_err( Maj::string("{} is not a vector"), maj_list!(vec)) } }
32.11. (vec-remove vec pos)
pub fn maj_vec_remove(pos: Gc<Maj>, vec: Gc<Maj>) -> Gc<Maj> { use crate::core::types::MajVector; let index = match pos.clone().to_integer() { Some(x) => { if x < 0 { return maj_err( Maj::string( "Index {} is out of bounds in {}"), maj_list!(pos, vec)); } x as usize }, None => { return maj_err( Maj::string("{} is not an integer"), maj_list!(pos)); }, }; if let Maj::Vector(vv) = &*vec { match vv { MajVector::Integer(v) => { let len = v.borrow().len(); if index >= len { maj_err( Maj::string( "Index {} is out of bounds in {}"), maj_list!(pos, vec)) } else { let value = v.borrow_mut().remove(index); Maj::integer(value) } }, MajVector::Float(v) => { let len = v.borrow().len(); if index >= len { maj_err( Maj::string( "Index {} is out of bounds in {}"), maj_list!(pos, vec)) } else { let value = v.borrow_mut().remove(index); Maj::float(value) } }, MajVector::Char(s) => { let len = s.borrow().chars().count(); if index >= len { maj_err( Maj::string( "Index {} is out of bounds in {}"), maj_list!(pos, vec)) } else { let value = s.borrow_mut().remove(index); Maj::character(value) } }, MajVector::Any(v) => { let len = v.borrow().len(); if index >= len { maj_err( Maj::string( "Index {} is out of bounds in {}"), maj_list!(pos, vec)) } else { v.borrow_mut().remove(index) } }, } } else { maj_err(Maj::string("{} is not a vector"), maj_list!(vec)) } }
33. Funções customizadas
33.1. (gc)
pub fn maj_gc() -> Gc<Maj> { use gc::force_collect; force_collect(); Maj::nil() }
33.2. (print-env type)
fn maj_print_env( mut state: &mut MajState, args: Gc<Maj>, env: Gc<Maj> ) -> Gc<Maj> { use crate::printing::maj_format_env; let is_global = maj_eq(maj_car(args.clone()), Maj::symbol(&mut state, "global")) .to_bool(); let is_lexical = maj_eq(maj_car(args.clone()), Maj::symbol(&mut state, "lexical")) .to_bool(); if is_global { println!("{}", state); Maj::nil() } else if is_lexical { println!("{}", maj_format_env(&state, env)); Maj::nil() } else { maj_err(Maj::string("Unknown environment type {}"), maj_list!(maj_car(args))) } }
33.3. (stack-state)
fn maj_stack_state() -> Gc<Maj> { match stacker::remaining_stack() { Some(n) => { println!("Remaining stack: {}B (roughly {}KB)", n, n / 1024); use std::convert::TryInto; match n.try_into() { Ok(n) => Maj::integer(n), Err(_) => Maj::t() } }, None => { println!("Couldn't query stack state"); Maj::nil() } } }
34. Registro em contexto global
pub fn maj_gen_primitives(state: &mut MajState) { use crate::axioms::{ MajPrimFn, MajPrimArgs }; let primitives: Vec<(&str, MajPrimArgs, MajPrimFn)> = vec![ ("cons", MajPrimArgs::Required(2), |_, args, _| { maj_destructure_args!(args, first, rest, second); maj_cons(first, second) }), ("car", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_car(first) }), ("cdr", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_cdr(first) }), ("copy", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_copy(first) }), ("length", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_length(first) }), ("depth", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_depth(first) }), ("type", MajPrimArgs::Required(1), |mut state, args, _| { maj_destructure_args!(args, first); maj_type(&mut state, first) }), ("intern", MajPrimArgs::Required(1), |mut state, args, _| { maj_destructure_args!(args, first); maj_intern(&mut state, first) }), ("name", MajPrimArgs::Required(1), |mut state, args, _| { maj_destructure_args!(args, first); maj_name(&mut state, first) }), ("get-environment", MajPrimArgs::Required(1), |mut state, args, env| { maj_destructure_args!(args, first); maj_get_environment(&mut state, first, env) }), ("coin", MajPrimArgs::None, |_, _, _| maj_coin()), ("sys", MajPrimArgs::Variadic(1), |_, args, _| { maj_destructure_args!(args, first, rest); maj_sys(first, rest) }), ("format", MajPrimArgs::Variadic(1), |state, args, _| { maj_destructure_args!(args, first, rest); maj_format_prim(&state, first, rest) }), ("err", MajPrimArgs::Variadic(1), |_, args, _| { maj_destructure_args!(args, first, rest); maj_err(first, rest) }), ("warn", MajPrimArgs::Variadic(1), |mut state, args, env| { maj_destructure_args!(args, first, rest); maj_warn(&mut state, first, rest, env) }), ("list", MajPrimArgs::Variadic(0), |_, args, _| maj_list(args)), ("append", MajPrimArgs::Variadic(0), |_, args, _| maj_append(args)), ("last", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_last(first) }), ("reverse", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_reverse(first) }), ("nth", MajPrimArgs::Required(2), |_, args, _| { maj_destructure_args!(args, first, rest, second); maj_nth(first, second) }), ("nthcdr", MajPrimArgs::Required(2), |_, args, _| { maj_destructure_args!(args, first, rest, second); maj_nthcdr(first, second) }), ("macroexpand-1", MajPrimArgs::Required(1), |mut state, args, env| { maj_destructure_args!(args, first); let (result, _) = maj_macroexpand_1(&mut state, first, env); result }), ("not", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_not(first) }), ("gensym", MajPrimArgs::None, |mut state, _, _| maj_gensym(&mut state)), ("iota", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_iota(first) }), // Number functions ("number-coerce", MajPrimArgs::Required(2), |mut state, args, _| { maj_destructure_args!(args, first, rest, second); maj_number_coerce(&mut state, first, second) }), ("real-part", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_real_part(first) }), ("imag-part", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_imag_part(first) }), ("numer", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_numer(first) }), ("denom", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_denom(first) }), ("richest-number-type", MajPrimArgs::Required(2), |mut state, args, _| { maj_destructure_args!(args, first, rest, second); maj_richest_number_type(&mut state, first, second) }), ("rich-number-coerce", MajPrimArgs::Required(2), |mut state, args, _| { maj_destructure_args!(args, first, rest, second); maj_rich_number_coerce(&mut state, first, second) }), ("=", MajPrimArgs::Variadic(2), |mut state, args, env| { maj_destructure_args!(args, first, r, second, rest); maj_arithm_eq(&mut state, env, first, second, rest) }), ("float=", MajPrimArgs::Required(2), |mut state, args, env| { maj_destructure_args!(args, first, r, second); maj_arithm_floateq(&mut state, env, first, second) }), (">", MajPrimArgs::Variadic(2), |mut state, args, _| { maj_destructure_args!(args, first, r, second, rest); maj_arithm_greater(&mut state, first, second, rest) }), ("<", MajPrimArgs::Variadic(2), |mut state, args, _| { maj_destructure_args!(args, first, r, second, rest); maj_arithm_lesser(&mut state, first, second, rest) }), (">=", MajPrimArgs::Variadic(2), |mut state, args, env| { maj_destructure_args!(args, first, r, second, rest); maj_arithm_geq(&mut state, env, first, second, rest) }), ("<=", MajPrimArgs::Variadic(2), |mut state, args, env| { maj_destructure_args!(args, first, r, second, rest); maj_arithm_leq(&mut state, env, first, second, rest) }), ("+", MajPrimArgs::Variadic(0), |mut state, args, env| { maj_arithm_plus(&mut state, env, args) }), ("-", MajPrimArgs::Variadic(0), |mut state, args, env| { maj_arithm_minus(&mut state, env, args) }), ("*", MajPrimArgs::Variadic(0), |mut state, args, env| { maj_arithm_times(&mut state, env, args) }), ("/", MajPrimArgs::Variadic(0), |mut state, args, env| { maj_arithm_divide(&mut state, env, args) }), // Stream functions ("open-stream", MajPrimArgs::Required(2), |mut state, args, _| { maj_destructure_args!(args, first, rest, second); maj_open_stream(&mut state, first, second) }), ("close-stream", MajPrimArgs::Required(1), |mut state, args, _| { maj_destructure_args!(args, first); maj_close_stream(&mut state, first) }), ("stat", MajPrimArgs::Required(1), |mut state, args, _| { maj_destructure_args!(args, first); maj_stat(&mut state, first) }), ("read-char", MajPrimArgs::Required(1), |mut state, args, _| { maj_destructure_args!(args, first); maj_read_char(&mut state, first) }), ("peek-char", MajPrimArgs::Required(1), |mut state, args, _| { maj_destructure_args!(args, first); maj_peek_char(&mut state, first) }), ("write-char", MajPrimArgs::Required(2), |mut state, args, _| { maj_destructure_args!(args, first, rest, second); maj_write_char(&mut state, first, second) }), ("write-string", MajPrimArgs::Required(2), |mut state, args, _| { maj_destructure_args!(args, first, rest, second); maj_write_string(&mut state, first, second) }), ("write", MajPrimArgs::Required(2), |mut state, args, _| { maj_destructure_args!(args, first, rest, second); maj_write(&mut state, first, second) }), ("terpri", MajPrimArgs::None, |mut state, _, env| { maj_terpri(&mut state, env) }), ("display", MajPrimArgs::Required(1), |mut state, args, env| { maj_destructure_args!(args, first); maj_display(&mut state, first, env) }), ("pretty-display", MajPrimArgs::Required(1), |mut state, args, env| { maj_destructure_args!(args, first); maj_pretty_display(&mut state, first, env) }), ("print", MajPrimArgs::Variadic(1), |mut state, args, env| { maj_destructure_args!(args, first, rest); maj_print(&mut state, first, rest, env) }), ("load", MajPrimArgs::Required(1), |mut state, args, env| { maj_destructure_args!(args, first); maj_load(&mut state, env, first) }), // Vector functions ("vec-type", MajPrimArgs::Required(1), |mut state, args, _| { maj_destructure_args!(args, first); maj_vec_type(&mut state, first) }), ("vec-push", MajPrimArgs::Required(2), |mut state, args, _| { maj_destructure_args!(args, first, rest, second); maj_vec_push(&mut state, first, second) }), ("vec-insert", MajPrimArgs::Required(3), |mut state, args, _| { maj_destructure_args!(args, first, rest, second, sndrst, third); maj_vec_insert(&mut state, first, second, third) }), ("vec-coerce", MajPrimArgs::Required(2), |mut state, args, _| { maj_destructure_args!(args, first, rest, second); maj_vec_coerce(&mut state, first, second) }), ("vector", MajPrimArgs::Variadic(0), |mut state, args, _| { maj_vector(&mut state, args) }), ("vec-length", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_vec_length(first) }), ("vec-pop", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_vec_pop(first) }), ("vec-deq", MajPrimArgs::Required(1), |_, args, _| { maj_destructure_args!(args, first); maj_vec_deq(first) }), ("vec-at", MajPrimArgs::Required(2), |_, args, _| { maj_destructure_args!(args, first, rest, second); maj_vec_at(first, second) }), ("vec-set", MajPrimArgs::Required(3), |_, args, _| { maj_destructure_args!(args, first, rest, second, snd_rest, third); maj_vec_set(first, second, third) }), ("vec-remove", MajPrimArgs::Required(2), |_, args, _| { maj_destructure_args!(args, first, rest, second); maj_vec_remove(first, second) }), // Non-standard functions ("gc", MajPrimArgs::None, |_, _, _| maj_gc()), ("print-env", MajPrimArgs::Required(1), maj_print_env), ("stack-state", MajPrimArgs::None, |_, _, _| maj_stack_state()), ]; for primitive in primitives.iter() { let (name, arity, f) = primitive; state.register_primitive(name, *arity, *f); } }