From f6c30e052821b99dc2b708c2e4327f08632258bc Mon Sep 17 00:00:00 2001 From: K1630549 Date: Thu, 17 Oct 2019 17:08:56 +0100 Subject: [PATCH] Add sqrt primitive. This adds the sqrt primitive to yksom for Int, BigInt and Double. --- Cargo.toml | 1 + lang_tests/double12.som | 14 ++++++++++++++ lang_tests/int26.som | 16 ++++++++++++++++ lang_tests/int27.som | 11 +++++++++++ lang_tests/int28.som | 11 +++++++++++ lang_tests/int29.som | 18 ++++++++++++++++++ lib/SOM/Double.som | 1 + lib/SOM/Integer.som | 1 + src/lib/compiler/ast_to_instrs.rs | 1 + src/lib/compiler/instrs.rs | 1 + src/lib/vm/core.rs | 6 ++++++ src/lib/vm/objects/double.rs | 4 ++++ src/lib/vm/objects/integers.rs | 10 +++++++++- src/lib/vm/objects/mod.rs | 5 +++++ src/lib/vm/val.rs | 17 +++++++++++++++++ 15 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 lang_tests/double12.som create mode 100644 lang_tests/int26.som create mode 100644 lang_tests/int27.som create mode 100644 lang_tests/int28.som create mode 100644 lang_tests/int29.som diff --git a/Cargo.toml b/Cargo.toml index 65516a39..2dad22b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ itertools = "0.8" lrlex = "0.4" lrpar = "0.4" num-bigint = "0.2" +num-integer = "0.1" num_enum = "0.3" num-traits = "0.2" natrob = { git="https://github.com/softdevteam/natrob", features=["abgc"] } diff --git a/lang_tests/double12.som b/lang_tests/double12.som new file mode 100644 index 00000000..b1bd3796 --- /dev/null +++ b/lang_tests/double12.som @@ -0,0 +1,14 @@ +" +VM: + status: success + stdout: + 1.1 + NaN +" + +double12 = ( + run = ( + (1.21 sqrt) println. + (-1.1 sqrt) println. + ) +) \ No newline at end of file diff --git a/lang_tests/int26.som b/lang_tests/int26.som new file mode 100644 index 00000000..85bb233d --- /dev/null +++ b/lang_tests/int26.som @@ -0,0 +1,16 @@ +" +VM: + status: success + stdout: + 5 + 1267650600228229401496703205376 + 1.7320508075688772 +" + +int26 = ( + run = ( + (25 sqrt) println. + ((1 << 200) sqrt) println. + (3 sqrt) println. + ) +) \ No newline at end of file diff --git a/lang_tests/int27.som b/lang_tests/int27.som new file mode 100644 index 00000000..76707b46 --- /dev/null +++ b/lang_tests/int27.som @@ -0,0 +1,11 @@ +" +VM: + status: error + stderr: DomainError +" + +int27 = ( + run = ( + -1 sqrt. + ) +) \ No newline at end of file diff --git a/lang_tests/int28.som b/lang_tests/int28.som new file mode 100644 index 00000000..5a54a2bc --- /dev/null +++ b/lang_tests/int28.som @@ -0,0 +1,11 @@ +" +VM: + status: error + stderr: DomainError +" + +int28 = ( + run = ( + (-1 << 200) sqrt. + ) +) \ No newline at end of file diff --git a/lang_tests/int29.som b/lang_tests/int29.som new file mode 100644 index 00000000..e55cc1d7 --- /dev/null +++ b/lang_tests/int29.som @@ -0,0 +1,18 @@ +" +VM: + status: success + stdout: + Integer + Integer + Double + Integer +" + +int29 = ( + run = ( + (4 sqrt class) println. + ((1 << 200) sqrt class) println. + (3 sqrt class) println. + ((1 << 199) sqrt class) println. + ) +) \ No newline at end of file diff --git a/lib/SOM/Double.som b/lib/SOM/Double.som index 8c897ac6..c1c7eb13 100644 --- a/lib/SOM/Double.som +++ b/lib/SOM/Double.som @@ -8,5 +8,6 @@ Double = ( >= argument = ( ^(self < argument) not ) <= argument = ( ^(self < argument) or: [ self = argument ] ) negative = ( ^self < 0.0 ) + sqrt = primitive asString = primitive ) diff --git a/lib/SOM/Integer.som b/lib/SOM/Integer.som index 41a9be65..655427aa 100644 --- a/lib/SOM/Integer.som +++ b/lib/SOM/Integer.som @@ -11,6 +11,7 @@ Integer = ( >= argument = primitive << argument = primitive bitXor: argument = primitive + sqrt = primitive asString = primitive to: limit do: block = ( diff --git a/src/lib/compiler/ast_to_instrs.rs b/src/lib/compiler/ast_to_instrs.rs index 6ae0dc93..4604e154 100644 --- a/src/lib/compiler/ast_to_instrs.rs +++ b/src/lib/compiler/ast_to_instrs.rs @@ -238,6 +238,7 @@ impl<'a> Compiler<'a> { requires_args(1)?; Ok(cobjects::MethodBody::Primitive(Primitive::BitXor)) } + "sqrt" => Ok(cobjects::MethodBody::Primitive(Primitive::Sqrt)), "asString" => Ok(cobjects::MethodBody::Primitive(Primitive::AsString)), "class" => Ok(cobjects::MethodBody::Primitive(Primitive::Class)), "concatenate:" => Ok(cobjects::MethodBody::Primitive(Primitive::Concatenate)), diff --git a/src/lib/compiler/instrs.rs b/src/lib/compiler/instrs.rs index a4e1d9cf..d2e5ba62 100644 --- a/src/lib/compiler/instrs.rs +++ b/src/lib/compiler/instrs.rs @@ -53,6 +53,7 @@ pub enum Primitive { RefEquals, Restart, Shl, + Sqrt, Sub, /// Is this `value` (0), `value:` (1), or `value:with:` (2)? Value(u8), diff --git a/src/lib/vm/core.rs b/src/lib/vm/core.rs index 6385d783..ef1eee26 100644 --- a/src/lib/vm/core.rs +++ b/src/lib/vm/core.rs @@ -41,6 +41,8 @@ pub enum VMError { /// A value which can't be represented in an `usize`. CantRepresentAsUsize, DivisionByZero, + /// A value which is mathematically undefined. + DomainError, /// The VM is trying to exit. Exit, /// Tried to perform a `Val::downcast` operation on a non-boxed `Val`. Note that `expected` @@ -465,6 +467,10 @@ impl VM { self.stack_push(stry!(rcv.shl(self, self.stack_pop()))); SendReturn::Val } + Primitive::Sqrt => { + self.stack_push(stry!(rcv.sqrt(self))); + SendReturn::Val + } Primitive::Sub => { self.stack_push(stry!(rcv.sub(self, self.stack_pop()))); SendReturn::Val diff --git a/src/lib/vm/objects/double.rs b/src/lib/vm/objects/double.rs index c368c8e5..9321d9dd 100644 --- a/src/lib/vm/objects/double.rs +++ b/src/lib/vm/objects/double.rs @@ -91,6 +91,10 @@ impl Obj for Double { } } + fn sqrt(&self, vm: &VM) -> Result> { + Ok(Double::new(vm, self.val.sqrt())) + } + fn ref_equals(&self, vm: &VM, other: Val) -> Result> { let b = if let Some(rhs) = other.try_downcast::(vm) { self.val == rhs.double() diff --git a/src/lib/vm/objects/integers.rs b/src/lib/vm/objects/integers.rs index b6cd40e9..b2d2116a 100644 --- a/src/lib/vm/objects/integers.rs +++ b/src/lib/vm/objects/integers.rs @@ -17,7 +17,7 @@ use std::convert::TryFrom; use abgc_derive::GcLayout; use num_bigint::BigInt; -use num_traits::{FromPrimitive, ToPrimitive}; +use num_traits::{FromPrimitive, ToPrimitive, Zero}; use crate::vm::{ core::{VMError, VM}, @@ -155,6 +155,14 @@ impl Obj for ArbInt { } } + fn sqrt(&self, vm: &VM) -> Result> { + if self.val < Zero::zero() { + Err(Box::new(VMError::DomainError)) + } else { + ArbInt::new(vm, self.val.sqrt()) + } + } + fn ref_equals(&self, vm: &VM, other: Val) -> Result> { let b = if let Some(rhs) = other.try_downcast::(vm) { self.val == rhs.val diff --git a/src/lib/vm/objects/mod.rs b/src/lib/vm/objects/mod.rs index 4f404a62..be4f7713 100644 --- a/src/lib/vm/objects/mod.rs +++ b/src/lib/vm/objects/mod.rs @@ -110,6 +110,11 @@ pub trait Obj: std::fmt::Debug + abgc::GcLayout { unimplemented!(); } + /// Produces a new `Val` which is the square root of this. + fn sqrt(&self, _: &VM) -> Result> { + unimplemented!(); + } + /// Is this `Val` reference equality equal to `other`? Only number types are likely to want to /// override this. fn ref_equals(&self, vm: &VM, other: Val) -> Result> { diff --git a/src/lib/vm/val.rs b/src/lib/vm/val.rs index e29b7e49..db299551 100644 --- a/src/lib/vm/val.rs +++ b/src/lib/vm/val.rs @@ -420,6 +420,23 @@ impl Val { self.tobj(vm).unwrap().shl(vm, other) } + /// Produces a new `Val` which is the square root of this. + pub fn sqrt(&self, vm: &VM) -> Result> { + if let Some(lhs) = self.as_isize(vm) { + if lhs < 0 { + return Err(Box::new(VMError::DomainError)); + } else { + let result = (lhs as f64).sqrt(); + if result.round() == result { + return Val::from_isize(vm, result as isize); + } else { + return Ok(Double::new(vm, result)); + } + } + } + self.tobj(vm).unwrap().sqrt(vm) + } + pub fn to_strval(&self, vm: &VM) -> Result> { debug_assert!(!self.is_illegal()); match self.valkind() {