fix imaginary, refactor
This commit is contained in:
parent
0560847753
commit
59f3e320e3
6 changed files with 214 additions and 113 deletions
|
@ -63,7 +63,8 @@ impl Highlighter for TalcHelper {
|
|||
| TokenKind::True
|
||||
| TokenKind::False
|
||||
| TokenKind::Integer
|
||||
| TokenKind::Float => "\x1b[93m",
|
||||
| TokenKind::Float
|
||||
| TokenKind::Imaginary => "\x1b[93m",
|
||||
TokenKind::String => "\x1b[92m",
|
||||
TokenKind::Symbol => "\x1b[96m",
|
||||
_ => "",
|
||||
|
|
|
@ -76,11 +76,11 @@ impl Display for Exception {
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! exception {
|
||||
($exc_ty:expr, $fstr:literal, $($arg:expr),*) => {
|
||||
($exc_ty:expr, $($t:tt)*) => {
|
||||
$crate::exception::Exception::new_with_msg(
|
||||
$exc_ty,
|
||||
$crate::lstring::LString::from(
|
||||
format!($fstr, $($arg),*)
|
||||
format!($($t)*)
|
||||
).into()
|
||||
)
|
||||
};
|
||||
|
|
|
@ -67,6 +67,7 @@ pub enum TokenKind {
|
|||
Identifier,
|
||||
Integer,
|
||||
Float,
|
||||
Imaginary,
|
||||
String,
|
||||
Symbol,
|
||||
And,
|
||||
|
@ -154,6 +155,7 @@ impl TokenKind {
|
|||
K::Identifier => "identifier",
|
||||
K::Integer => "integer",
|
||||
K::Float => "float",
|
||||
K::Imaginary => "imaginary",
|
||||
K::String => "string",
|
||||
K::Symbol => "symbol",
|
||||
K::And => "'and'",
|
||||
|
@ -324,6 +326,15 @@ impl<'s> Lexer<'s> {
|
|||
}
|
||||
}
|
||||
|
||||
fn next_imag(&mut self) -> Result<Token<'s>> {
|
||||
self.next()?;
|
||||
if is_xid_start(self.peek()?) {
|
||||
self.unexpected()
|
||||
} else {
|
||||
self.emit(K::Imaginary)
|
||||
}
|
||||
}
|
||||
|
||||
fn next_float(&mut self, mut has_e: bool) -> Result<Token<'s>> {
|
||||
while !has_e {
|
||||
while matches!(self.peek()?, '_' | '0'..='9') {
|
||||
|
@ -331,6 +342,7 @@ impl<'s> Lexer<'s> {
|
|||
}
|
||||
match self.peek()? {
|
||||
'e' => { self.next()?; has_e = true }
|
||||
'i' => return self.next_imag(),
|
||||
c if is_xid_start(c) => return self.unexpected(),
|
||||
_ => return self.emit(K::Float)
|
||||
}
|
||||
|
@ -341,10 +353,10 @@ impl<'s> Lexer<'s> {
|
|||
while matches!(self.peek()?, '_' | '0'..='9') {
|
||||
self.next()?;
|
||||
}
|
||||
if is_xid_start(self.peek()?) {
|
||||
self.unexpected()
|
||||
} else {
|
||||
self.emit(K::Float)
|
||||
match self.peek()? {
|
||||
'i' => self.next_imag(),
|
||||
c if is_xid_start(c) => self.unexpected(),
|
||||
_ => self.emit(K::Float)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,8 +368,8 @@ impl<'s> Lexer<'s> {
|
|||
'o' => { self.next()?; return self.next_int_base(8) },
|
||||
's' => { self.next()?; return self.next_int_base(6) },
|
||||
'b' => { self.next()?; return self.next_int_base(2) },
|
||||
'0'..='9' | '.' | 'e' | 'i' => (),
|
||||
c if is_xid_start(c) => return self.unexpected(),
|
||||
'0'..='9' => (),
|
||||
_ => return self.emit(K::Integer)
|
||||
}
|
||||
}
|
||||
|
@ -367,6 +379,7 @@ impl<'s> Lexer<'s> {
|
|||
match self.peek()? {
|
||||
'r' => todo!("arbitrary radix integer literals"),
|
||||
'e' => { self.next()?; self.next_float(true) },
|
||||
'i' => self.next_imag(),
|
||||
'.' => {
|
||||
if self.peek_n(1) == Some('.') {
|
||||
self.emit(K::Integer)
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::iter::Peekable;
|
|||
use crate::{lstr, lstring::LStr, symbol::Symbol, value::Value};
|
||||
|
||||
use super::{ast::{BinaryOp, CatchBlock, Expr, ExprKind, LValue, UnaryOp}, parse_float, parse_int_literal, parse_str_escapes, Lexer, ParserError, Span, SpanParserError, Token, TokenKind};
|
||||
use num_complex::Complex64;
|
||||
use TokenKind as T;
|
||||
use ExprKind as E;
|
||||
|
||||
|
@ -179,6 +180,7 @@ impl TokenKind {
|
|||
| T::Try
|
||||
| T::Integer
|
||||
| T::Float
|
||||
| T::Imaginary
|
||||
| T::String
|
||||
| T::Symbol
|
||||
| T::True
|
||||
|
@ -371,6 +373,11 @@ impl<'s> Parser<'s> {
|
|||
.span_err(tok.span)?;
|
||||
Ok(E::Literal(x.into()).span(tok.span))
|
||||
},
|
||||
T::Imaginary => {
|
||||
let x = parse_float(&tok.content[..tok.content.len()-1])
|
||||
.span_err(tok.span)?;
|
||||
Ok(E::Literal(Complex64::new(0.0, x).into()).span(tok.span))
|
||||
},
|
||||
T::String => {
|
||||
let inner = &tok.content[1..tok.content.len()-1];
|
||||
let s = if &tok.content[..1] == "\"" {
|
||||
|
@ -554,7 +561,6 @@ impl<'s> Parser<'s> {
|
|||
|
||||
fn parse_assign(&mut self) -> Result<Expr<'s>> {
|
||||
if let Some(tok) = try_next!(self, T::Global | T::Var) {
|
||||
self.next()?;
|
||||
let name = expect!(self, T::Identifier);
|
||||
expect!(self, T::Equal);
|
||||
let val = self.parse_or()?;
|
||||
|
|
|
@ -5,7 +5,7 @@ use num_complex::{Complex64, ComplexFloat};
|
|||
use num_rational::Rational64;
|
||||
use num_traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Signed, Zero};
|
||||
|
||||
use crate::{exception::{exception, throw, Result}, lstring::LString, symbol::{SYM_END_ITERATION, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, value::range::RangeType, Vm};
|
||||
use crate::{exception::{throw, Result}, lstring::LString, symbol::{SYM_END_ITERATION, SYM_TYPE_ERROR, SYM_VALUE_ERROR}, value::range::RangeType, Vm};
|
||||
|
||||
use super::{function::{FuncAttrs, NativeFunc}, range::Range, HashValue, Value};
|
||||
|
||||
|
@ -40,7 +40,6 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::cast_precision_loss)]
|
||||
pub fn promote(a: Value, b: Value) -> (Value, Value) {
|
||||
use Value as V;
|
||||
match (&a, &b) {
|
||||
|
@ -61,6 +60,11 @@ pub fn promote(a: Value, b: Value) -> (Value, Value) {
|
|||
}
|
||||
|
||||
|
||||
////////////////////////
|
||||
// unary arithmetic //
|
||||
////////////////////////
|
||||
|
||||
|
||||
impl Neg for Value {
|
||||
type Output = Result<Self>;
|
||||
fn neg(self) -> Self::Output {
|
||||
|
@ -83,74 +87,65 @@ impl Neg for Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl Add<Value> for Value {
|
||||
type Output = Result<Self>;
|
||||
fn add(self, rhs: Value) -> Self::Output {
|
||||
impl Value {
|
||||
pub fn abs(self) -> Result<Self> {
|
||||
use Value as V;
|
||||
let (a, b) = promote(self, rhs);
|
||||
match (&a, &b) {
|
||||
(V::Int(x), V::Int(y)) => if let Some(v) = x.checked_add(y) {
|
||||
Ok(V::Int(v))
|
||||
match self {
|
||||
V::Int(x) => if let Some(x) = x.checked_abs() {
|
||||
Ok(V::Int(x))
|
||||
} else {
|
||||
throw!(*SYM_VALUE_ERROR, "overflow when adding {a} and {b}")
|
||||
throw!(*SYM_VALUE_ERROR, "overflow when finding absolute value of {self}")
|
||||
},
|
||||
(V::Ratio(x), V::Ratio(y)) => if let Some(v) = x.checked_add(y) {
|
||||
Ok(V::Ratio(v))
|
||||
V::Ratio(x) => if let Some((x, _)) = ratio_checked_absign(&x) {
|
||||
Ok(V::Ratio(x))
|
||||
} else {
|
||||
throw!(*SYM_VALUE_ERROR, "overflow when adding {a} and {b}")
|
||||
},
|
||||
(V::Float(x), V::Float(y)) => Ok(V::Float(x + y)),
|
||||
(V::Complex(x), V::Complex(y)) => Ok(V::Complex(x + y)),
|
||||
(l, r) => throw!(*SYM_TYPE_ERROR, "cannot add {l:#} and {r:#}")
|
||||
throw!(*SYM_VALUE_ERROR, "overflow when finding absolute value of {self}")
|
||||
}
|
||||
V::Float(x) => Ok(V::Float(x.abs())),
|
||||
V::Complex(x) => Ok(V::Float(x.norm())),
|
||||
a => throw!(*SYM_TYPE_ERROR, "cannot negate {a:#}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Value> for Value {
|
||||
type Output = Result<Self>;
|
||||
fn sub(self, rhs: Value) -> Self::Output {
|
||||
use Value as V;
|
||||
let (a, b) = promote(self, rhs);
|
||||
match (&a, &b) {
|
||||
(V::Int(x), V::Int(y)) => if let Some(v) = x.checked_sub(y) {
|
||||
Ok(V::Int(v))
|
||||
} else {
|
||||
throw!(*SYM_VALUE_ERROR, "overflow when subtracting {a} and {b}")
|
||||
},
|
||||
(V::Ratio(x), V::Ratio(y)) => if let Some(v) = x.checked_sub(y) {
|
||||
Ok(V::Ratio(v))
|
||||
} else {
|
||||
throw!(*SYM_VALUE_ERROR, "overflow when subtracting {a} and {b}")
|
||||
},
|
||||
(V::Float(x), V::Float(y)) => Ok(V::Float(x - y)),
|
||||
(V::Complex(x), V::Complex(y)) => Ok(V::Complex(x - y)),
|
||||
(l, r) => throw!(*SYM_TYPE_ERROR, "cannot subtract {l:#} and {r:#}")
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// binary arithmetic //
|
||||
/////////////////////////
|
||||
|
||||
|
||||
macro_rules! impl_value_arith {
|
||||
($trait:ident, $name:ident, $checked:ident, $op:tt, $verb:literal) => {
|
||||
|
||||
impl $trait<Value> for Value {
|
||||
type Output = Result<Self>;
|
||||
fn $name(self, rhs: Value) -> Self::Output {
|
||||
use Value as V;
|
||||
let (a, b) = promote(self, rhs);
|
||||
match (&a, &b) {
|
||||
(V::Int(x), V::Int(y)) => if let Some(v) = x.$checked(y) {
|
||||
Ok(V::Int(v))
|
||||
} else {
|
||||
throw!(*SYM_VALUE_ERROR, concat!("overflow when ", $verb, "ing {} and {}"), a, b)
|
||||
},
|
||||
(V::Ratio(x), V::Ratio(y)) => if let Some(v) = x.$checked(y) {
|
||||
Ok(V::Ratio(v))
|
||||
} else {
|
||||
throw!(*SYM_VALUE_ERROR, concat!("overflow when ", $verb, "ing {} and {}"), a, b)
|
||||
},
|
||||
(V::Float(x), V::Float(y)) => Ok(V::Float(x $op y)),
|
||||
(V::Complex(x), V::Complex(y)) => Ok(V::Complex(x $op y)),
|
||||
(l, r) => throw!(*SYM_TYPE_ERROR, concat!("cannot ", $verb, " {:#} and {:#}"), l, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
impl Mul<Value> for Value {
|
||||
type Output = Result<Self>;
|
||||
fn mul(self, rhs: Value) -> Self::Output {
|
||||
use Value as V;
|
||||
let (a, b) = promote(self, rhs);
|
||||
match (&a, &b) {
|
||||
(V::Int(x), V::Int(y)) => if let Some(v) = x.checked_mul(y) {
|
||||
Ok(V::Int(v))
|
||||
} else {
|
||||
throw!(*SYM_VALUE_ERROR, "overflow when multiplying {a} and {b}")
|
||||
},
|
||||
(V::Ratio(x), V::Ratio(y)) => if let Some(v) = x.checked_mul(y) {
|
||||
Ok(V::Ratio(v))
|
||||
} else {
|
||||
throw!(*SYM_VALUE_ERROR, "overflow when multiplying {a} and {b}")
|
||||
},
|
||||
(V::Float(x), V::Float(y)) => Ok(V::Float(x * y)),
|
||||
(V::Complex(x), V::Complex(y)) => Ok(V::Complex(x * y)),
|
||||
(l, r) => throw!(*SYM_TYPE_ERROR, "cannot multiply {l:#} and {r:#}")
|
||||
}
|
||||
}
|
||||
}
|
||||
impl_value_arith!(Add, add, checked_add, +, "add");
|
||||
impl_value_arith!(Sub, sub, checked_sub, -, "subtract");
|
||||
impl_value_arith!(Mul, mul, checked_mul, *, "multiply");
|
||||
|
||||
impl Div<Value> for Value {
|
||||
type Output = Result<Self>;
|
||||
|
@ -174,42 +169,35 @@ impl Div<Value> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////
|
||||
// modulo and integer division //
|
||||
///////////////////////////////////
|
||||
|
||||
|
||||
#[inline]
|
||||
fn ipow(n: i64, p: u64) -> Option<i64> {
|
||||
match (n, p) {
|
||||
(0, 0) => None,
|
||||
(0, _) => Some(0),
|
||||
(_, 0) => Some(1),
|
||||
(1, _) => Some(1),
|
||||
(-1, p) => (-1_i64).checked_pow((p % 2) as u32),
|
||||
(_, p) if p > u32::MAX as u64 => None,
|
||||
(n, p) => n.checked_pow(p as u32),
|
||||
}
|
||||
fn ratio_checked_absign(r: &Rational64) -> Option<(Rational64, Rational64)> {
|
||||
let a = if r.is_negative() {
|
||||
Rational64::ZERO.checked_sub(r)?
|
||||
} else {
|
||||
*r
|
||||
};
|
||||
Some((a, r.signum()))
|
||||
}
|
||||
|
||||
#[expect(clippy::cast_sign_loss)]
|
||||
#[inline]
|
||||
fn rpow(n: i64, d: i64, p: i64) -> Option<(i64, i64)> {
|
||||
match p {
|
||||
i64::MIN => match (n, d) {
|
||||
(0, _) => Some((0, 1)),
|
||||
(1, 1) => Some((1, 1)),
|
||||
(-1, 1) => Some((-1, 1)),
|
||||
_ => None,
|
||||
}
|
||||
0.. => Some((ipow(n, p as u64)?, ipow(d, p as u64)?)),
|
||||
_ => Some((ipow(d, (-p) as u64)?, ipow(n, (-p) as u64)?)),
|
||||
}
|
||||
}
|
||||
|
||||
fn ratio_checked_rem_euclid(r1: &Rational64, r2: &Rational64) -> Option<Rational64> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn ratio_checked_div_euclid(r1: &Rational64, r2: &Rational64) -> Option<Rational64> {
|
||||
todo!()
|
||||
let (r2_abs, r2_sgn) = ratio_checked_absign(r2)?;
|
||||
Some(r1.checked_div(&r2_abs)?.floor() * r2_sgn)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ratio_checked_rem_euclid(r1: &Rational64, r2: &Rational64) -> Option<Rational64> {
|
||||
let q = ratio_checked_div_euclid(r1, r2)?;
|
||||
r1.checked_sub(&r2.checked_mul(&q)?)
|
||||
|
||||
}
|
||||
|
||||
|
||||
impl Value {
|
||||
pub fn modulo(self, rhs: Value) -> Result<Self> {
|
||||
use Value as V;
|
||||
|
@ -267,7 +255,42 @@ impl Value {
|
|||
(l, r) => throw!(*SYM_TYPE_ERROR, "cannot integer divide {l:#} and {r:#}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////
|
||||
// exponentiation //
|
||||
//////////////////////
|
||||
|
||||
|
||||
#[inline]
|
||||
fn ipow(n: i64, p: u64) -> Option<i64> {
|
||||
match (n, p) {
|
||||
(0, 0) => None,
|
||||
(0, _) => Some(0),
|
||||
(_, 0) => Some(1),
|
||||
(1, _) => Some(1),
|
||||
(-1, p) => (-1_i64).checked_pow((p % 2) as u32),
|
||||
(_, p) if p > u32::MAX as u64 => None,
|
||||
(n, p) => n.checked_pow(p as u32),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rpow(n: i64, d: i64, p: i64) -> Option<(i64, i64)> {
|
||||
match p {
|
||||
i64::MIN => match (n, d) {
|
||||
(0, _) => Some((0, 1)),
|
||||
(1, 1) => Some((1, 1)),
|
||||
(-1, 1) => Some((-1, 1)),
|
||||
_ => None,
|
||||
}
|
||||
0.. => Some((ipow(n, p as u64)?, ipow(d, p as u64)?)),
|
||||
_ => Some((ipow(d, (-p) as u64)?, ipow(n, (-p) as u64)?)),
|
||||
}
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn pow(self, rhs: Value) -> Result<Self> {
|
||||
use Value as V;
|
||||
if let (V::Ratio(x), V::Int(y)) = (&self, &rhs) {
|
||||
|
@ -304,6 +327,12 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////
|
||||
// Bitwise operations //
|
||||
//////////////////////////
|
||||
|
||||
|
||||
impl Shl<Value> for Value {
|
||||
type Output = Result<Value>;
|
||||
|
||||
|
@ -364,8 +393,13 @@ impl BitOr<Value> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
// Equality and ordering //
|
||||
/////////////////////////////
|
||||
|
||||
|
||||
impl PartialEq for Value {
|
||||
#[expect(clippy::cast_precision_loss)]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
use Value as V;
|
||||
use super::range::RangeType as Rty;
|
||||
|
@ -408,7 +442,6 @@ impl PartialEq for Value {
|
|||
}
|
||||
|
||||
impl PartialOrd for Value {
|
||||
#[expect(clippy::cast_precision_loss)]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
use Value as V;
|
||||
match (self, other) {
|
||||
|
@ -431,6 +464,12 @@ impl PartialOrd for Value {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
////////////
|
||||
// misc //
|
||||
////////////
|
||||
|
||||
|
||||
impl Value {
|
||||
pub fn val_cmp(&self, other: &Self) -> Result<Ordering> {
|
||||
match self.partial_cmp(other) {
|
||||
|
|
|
@ -67,6 +67,7 @@ pub fn load(vm: &mut Vm) {
|
|||
vm.set_global_name("isqrt", isqrt().into());
|
||||
vm.set_global_name("isprime", isprime().into());
|
||||
vm.set_global_name("factors", factors().into());
|
||||
vm.set_global_name("totient", totient().into());
|
||||
|
||||
vm.set_global_name("min", min().into());
|
||||
vm.set_global_name("max", max().into());
|
||||
|
@ -364,7 +365,7 @@ pub fn lcm(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
if g == 0 {
|
||||
Ok(Value::from(0))
|
||||
} else {
|
||||
Value::from(x/g) * Value::from(y)
|
||||
(Value::from(x)/Value::from(g))? * Value::from(y)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -381,7 +382,11 @@ pub fn lcmn(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
};
|
||||
let g = gcd_inner(l, a);
|
||||
if g == 0 { return Ok(Value::from(0)) };
|
||||
l = (l/g).wrapping_mul(a);
|
||||
let new_l = (Value::from(l).int_div(Value::from(g))? * Value::from(a))?;
|
||||
let Value::Int(new_l) = new_l else {
|
||||
unreachable!("int//int * int != int")
|
||||
};
|
||||
l = new_l;
|
||||
}
|
||||
|
||||
Ok(Value::from(l))
|
||||
|
@ -391,7 +396,7 @@ pub fn lcmn(vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
pub fn factors(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||
let [_, x] = unpack_args!(args);
|
||||
let Value::Int(mut x) = x else {
|
||||
throw!(*SYM_TYPE_ERROR, "factords expected integer argument, got {x:#}")
|
||||
throw!(*SYM_TYPE_ERROR, "factors expected integer argument, got {x:#}")
|
||||
};
|
||||
let mut factors = Vec::new();
|
||||
if x <= 1 {
|
||||
|
@ -424,6 +429,49 @@ pub fn factors(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
Ok(factors.into())
|
||||
}
|
||||
|
||||
fn totient_prime(n: &mut u64, p: u64) -> u64 {
|
||||
if *n % p != 0 {
|
||||
return 1
|
||||
}
|
||||
*n /= p;
|
||||
let mut v = p - 1;
|
||||
while *n % p == 0 {
|
||||
*n /= p;
|
||||
v *= p;
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
#[native_func(1)]
|
||||
pub fn totient(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||
let [_, x] = unpack_args!(args);
|
||||
let Value::Int(x) = x else {
|
||||
throw!(*SYM_TYPE_ERROR, "totient expected integer argument, got {x:#}")
|
||||
};
|
||||
if x <= 1 {
|
||||
return Ok(1.into())
|
||||
}
|
||||
let mut x = x as u64;
|
||||
let mut totient = 1;
|
||||
if x & 1 == 0 { x >>= 1; }
|
||||
while x & 1 == 0 {
|
||||
x >>= 1;
|
||||
totient <<= 1;
|
||||
}
|
||||
totient *= totient_prime(&mut x, 3);
|
||||
let mut i = 5;
|
||||
while x >= i*i {
|
||||
totient *= totient_prime(&mut x, i);
|
||||
i += 2;
|
||||
totient *= totient_prime(&mut x, i);
|
||||
i += 4;
|
||||
}
|
||||
if x > 1 {
|
||||
totient *= x - 1;
|
||||
}
|
||||
Ok((totient as i64).into())
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// numeric operations
|
||||
|
@ -669,22 +717,16 @@ pub fn arg(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
|||
#[native_func(1)]
|
||||
pub fn abs(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||
let [_, x] = unpack_args!(args);
|
||||
match x {
|
||||
Value::Int(x) => Ok(Value::Int(x.abs())),
|
||||
Value::Ratio(x) => Ok(Value::Ratio(if x < 0.into() { -x } else { x })),
|
||||
Value::Float(x) => Ok(Value::Float(x.abs())),
|
||||
Value::Complex(x) => Ok(Value::Float(x.norm())),
|
||||
x => throw!(*SYM_TYPE_ERROR, "abs expected numeric argument, got {x:#}"),
|
||||
}
|
||||
x.abs()
|
||||
}
|
||||
|
||||
#[native_func(1)]
|
||||
pub fn abs_sq(_: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||
let [_, x] = unpack_args!(args);
|
||||
match x {
|
||||
Value::Int(x) => Ok(Value::Int(x * x)),
|
||||
Value::Ratio(x) => Ok(Value::Ratio(x * x)),
|
||||
Value::Float(x) => Ok(Value::Float(x * x)),
|
||||
Value::Int(_) => x.clone() * x,
|
||||
Value::Ratio(_) => x.clone() * x,
|
||||
Value::Float(_) => x.clone() * x,
|
||||
Value::Complex(x) => Ok(Value::Float(x.norm_sqr())),
|
||||
x => throw!(*SYM_TYPE_ERROR, "abs_sq expected numeric argument, got {x:#}"),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue