Skip to content

Commit

Permalink
Implement From<number> for SExpr
Browse files Browse the repository at this point in the history
  • Loading branch information
cowuake committed Aug 15, 2024
1 parent 4a90c8e commit 2e3bde0
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 34 deletions.
2 changes: 1 addition & 1 deletion schemius/src/core/builtins/list_procs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ pub fn r_length(args: ProcedureArgs, _: ProcedureEnv) -> ProcedureOutput {
match args.s_car().unwrap() {
SExpr::List(list) => {
let len = list.access().s_len();
Ok(SExpr::Number(SNumber::Int(NativeInt::from(len as NativeInt))))
Ok(SExpr::from(len as NativeInt))
}
_ => Err(String::from("Exception in #<length>: expected a list")),
}
Expand Down
2 changes: 1 addition & 1 deletion schemius/src/core/builtins/number_procs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ macro_rules! fn_compute_sum_prod {
$(
pub fn $fn(args: ProcedureArgs, _: ProcedureEnv) -> ProcedureOutput {
match args.len() {
0 => Ok(SExpr::Number(SNumber::Int($neutral))),
0 => Ok(SExpr::from($neutral)),
_ => {
let mut res = SNumber::Int($neutral);

Expand Down
4 changes: 2 additions & 2 deletions schemius/src/core/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,14 @@ pub fn eval(expression: &SExpr, env: ProcedureEnv) -> EvalOutput {

#[cfg(test)]
mod tests {
use crate::core::s_expression::{s_number::SNumber, SExpr};
use crate::core::s_expression::SExpr;

use super::Evaluator;

#[test]
fn evaluator_ok_int() {
let evaluator = Evaluator::default();
let expression = SExpr::Number(SNumber::Int(0));
let expression = SExpr::from(0);
let res = evaluator.eval(&expression);

assert!(res.is_ok())
Expand Down
42 changes: 19 additions & 23 deletions schemius/src/core/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,9 @@ fn parse_token(line: &mut String, token: &str) -> Result<SExpr, String> {
match token {
tokens::TRUE => Ok(SExpr::Boolean(true)),
tokens::FALSE => Ok(SExpr::Boolean(false)),
tokens::NEGATIVE_NAN | tokens::POSITIVE_NAN => {
Ok(SExpr::Number(SNumber::Float(NativeFloat::NAN)))
}
tokens::NEGATIVE_INFINITY => Ok(SExpr::Number(SNumber::Float(NativeFloat::NEG_INFINITY))),
tokens::POSITIVE_INFINITY => Ok(SExpr::Number(SNumber::Float(NativeFloat::INFINITY))),
tokens::NEGATIVE_NAN | tokens::POSITIVE_NAN => Ok(SExpr::from(NativeFloat::NAN)),
tokens::NEGATIVE_INFINITY => Ok(SExpr::from(NativeFloat::NEG_INFINITY)),
tokens::POSITIVE_INFINITY => Ok(SExpr::from(NativeFloat::INFINITY)),
token if token.starts_with('"') => {
Ok(SExpr::String(SchemeString::new(token.get(1..token.len() - 1).unwrap().to_string())))
}
Expand Down Expand Up @@ -189,27 +187,25 @@ fn parse_token(line: &mut String, token: &str) -> Result<SExpr, String> {
let number = if n_prefixes == 1 { &token[2..] } else { &token[4..] };
match NativeInt::from_str_radix(number, radix) {
Ok(n) => match is_exact {
Some(true) | None => Ok(SExpr::Number(SNumber::Int(n))),
Some(false) => Ok(SExpr::Number(SNumber::Float(n as NativeFloat))),
Some(true) | None => Ok(SExpr::from(n)),
Some(false) => Ok(SExpr::from(n as NativeFloat)),
},
_ => match NativeBigInt::from_str_radix(number, radix) {
Ok(n) => match is_exact {
Some(true) | None => Ok(SExpr::Number(SNumber::BigInt(n))),
Some(false) => Ok(SExpr::Number(SNumber::Float(n.to_float().unwrap()))),
Some(true) | None => Ok(SExpr::from(n)),
Some(false) => Ok(SExpr::from(n.to_float().unwrap())),
},
_ => match NativeRational::from_str_radix(number, radix) {
Ok(q) => match is_exact {
Some(true) | None => Ok(SExpr::Number(SNumber::Rational(q))),
Some(false) => {
Ok(SExpr::Number(SNumber::Float(q.to_float().unwrap())))
}
Some(true) | None => Ok(SExpr::from(q)),
Some(false) => Ok(SExpr::from(q.to_float().unwrap())),
},
_ => match NativeFloat::from_str_radix(number, radix) {
Ok(f) => match is_exact {
Some(true) => Ok(SExpr::Number(SNumber::Rational(
NativeRational::from_float(f).unwrap(),
))),
Some(false) | None => Ok(SExpr::Number(SNumber::Float(f))),
Some(true) => {
Ok(SExpr::from(NativeRational::from_float(f).unwrap()))
}
Some(false) | None => Ok(SExpr::from(f)),
},
_ => Ok(SExpr::Symbol(token.to_string())),
},
Expand All @@ -218,15 +214,15 @@ fn parse_token(line: &mut String, token: &str) -> Result<SExpr, String> {
}
} else {
match token.parse::<NativeInt>() {
Ok(n) => Ok(SExpr::Number(SNumber::Int(n))),
Ok(n) => Ok(SExpr::from(n)),
_ => match token.parse::<NativeBigInt>() {
Ok(n) => Ok(SExpr::Number(SNumber::BigInt(n))),
Ok(n) => Ok(SExpr::from(n)),
_ => match token.parse::<NativeRational>() {
Ok(q) => Ok(SExpr::Number(SNumber::Rational(q))),
Ok(q) => Ok(SExpr::from(q)),
_ => match token.parse::<NativeFloat>() {
Ok(f) => Ok(SExpr::Number(SNumber::Float(f))),
Ok(f) => Ok(SExpr::from(f)),
_ => match token.parse::<NativeComplex>() {
Ok(c) => Ok(SExpr::Number(SNumber::Complex(c))),
Ok(c) => Ok(SExpr::from(c)),
_ => match COMPLEX_POLAR_REGEX.captures(token) {
Some(_) => Ok(parse_polar_complex(token)),
None => Ok(SExpr::Symbol(token.to_string())),
Expand Down Expand Up @@ -254,7 +250,7 @@ fn parse_polar_complex(token: &str) -> SExpr {
let magnitude = parts[0];
let angle = parts[1];

SExpr::Number(SNumber::Complex(NativeComplex::from_polar(magnitude, angle)))
SExpr::from(NativeComplex::from_polar(magnitude, angle))
}

#[cfg(test)]
Expand Down
91 changes: 84 additions & 7 deletions schemius/src/core/s_expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,41 @@ pub enum SExpr {
Ok,
}

macro_rules! impl_from_primitive {
($($source:ident, $target:ident)*) => {
$(
impl From<$source> for SExpr {
fn from(val: $source) -> Self {
SExpr::$target(val)
}
}
)*}
}

macro_rules! impl_from_number {
($($source:ident, $target:ident)*) => {
$(
impl From<$source> for SExpr {
fn from(val: $source) -> Self {
SExpr::Number(SNumber::$target(val))
}
}
)*}
}

impl_from_primitive! {
bool, Boolean
char, Char
}

impl_from_number! {
NativeInt, Int
NativeBigInt, BigInt
NativeRational, Rational
NativeComplex, Complex
NativeFloat, Float
}

impl fmt::Display for SExpr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expand Down Expand Up @@ -552,7 +587,7 @@ impl SExpr {
}

#[cfg(test)]
mod tests {
mod s_expression_tests {
use crate::core::builtins::Primitive;

use super::*;
Expand All @@ -565,20 +600,20 @@ mod tests {

#[test]
fn test_sexpr_as_int() {
let sexpr = SExpr::Number(SNumber::Int(42));
let sexpr = SExpr::from(42);
assert_eq!(sexpr.as_int().unwrap(), 42);
}

#[test]
fn test_sexpr_quote() {
let expression = SExpr::Number(SNumber::Int(42));
let expression = SExpr::from(42);
let quoted = expression.quote().unwrap();
assert!(quoted.is_list().unwrap() && quoted.is_quoted_list().unwrap());
}

#[test]
fn test_sexpr_unquote() {
let internal = SExpr::Number(SNumber::Int(42));
let internal = SExpr::from(42);
let expression = internal.quote().unwrap();
let unquoted = expression.unquote().unwrap();
assert!(unquoted.is_number().unwrap());
Expand All @@ -594,16 +629,58 @@ mod tests {
fn test_sexpr_is_applyable() {
let sexpr = SExpr::List(SchemeList::new(ListImplementation::from_iter([
SExpr::Procedure(Procedure::Primitive(Primitive::SUM)),
SExpr::Number(SNumber::Int(1)),
SExpr::Number(SNumber::Int(2)),
SExpr::from(1),
SExpr::from(2),
])));
assert!(sexpr.is_applyable().unwrap());
}

#[test]
fn test_sexpr_is_atom() {
let sexpr = SExpr::Number(SNumber::Int(NativeInt::from(3)));
let sexpr = SExpr::from(3);
let is_atom = sexpr.is_atom().unwrap();
assert!(is_atom)
}

#[test]
fn test_sexpr_from_int() {
let sexpr = SExpr::from(42);
assert!(sexpr.is_number().unwrap());
}

#[test]
fn test_sexpr_from_big_int() {
let sexpr = SExpr::from(NativeBigInt::from(42));
assert!(sexpr.is_number().unwrap());
}

#[test]
fn test_sexpr_from_rational() {
let sexpr = SExpr::from(NativeRational::new(NativeBigInt::from(1), NativeBigInt::from(2)));
assert!(sexpr.is_number().unwrap());
}

#[test]
fn test_sexpr_from_float() {
let sexpr = SExpr::from(NativeFloat::from(1.0));
assert!(sexpr.is_number().unwrap());
}

#[test]
fn test_sexpr_from_complex() {
let sexpr = SExpr::from(NativeComplex::new(NativeFloat::from(1.0), NativeFloat::from(2.0)));
assert!(sexpr.is_number().unwrap());
}

#[test]
fn test_sexpr_from_char() {
let sexpr = SExpr::from('a');
assert!(sexpr.is_char().unwrap());
}

#[test]
fn test_sexpr_from_bool() {
let sexpr = SExpr::from(true);
assert!(sexpr.is_boolean().unwrap());
}
}

0 comments on commit 2e3bde0

Please sign in to comment.