Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More comparisons #55

Merged
merged 2 commits into from
Oct 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions lang_tests/double10.som
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"
VM:
status: success
stdout:
false
true
true
true
false
true
false
false
false
true
true
false
true
true
true
false
"

double10 = (
run = (
(1.0 = 0) println.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be ==?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SOM is a little unusual (to our eyes) in this regadr. = means "check the values for equality". == means (roughly) "check the data pointer for equality" (though for integers this is overridden -- Python effectively does something similar).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Thanks for the explanation.

(1.0 = 1) println.
(1.0 ~= 0) println.
(1.0 ~= 1) println.

(1.0 < 1) println.
(1.0 < 2) println.
(2.0 < 0) println.

(1.0 > 1) println.
(1.0 > 2) println.
(2.0 > 0) println.

(1.0 >= 1) println.
Copy link
Member

@ptersilie ptersilie Oct 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, so in SOM, 1.0 == 1 is false, 1.0 > 1 is false, but 1.0 >= 1 is true?

Copy link
Contributor

@smarr smarr Oct 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

== is very different from the other two, and unrelated.

1.0 > 1 and 1 > 1 should yield both false, no? (minus issues with number representations for floating points, which hopefully do not matter for 1-like values, but will crop up with int-like values > 53-or-something bits).

And 1.0 >= 1 and 1 >= 1 should both be true in an ideal world (minus floating point issues)

Copy link
Member

@ptersilie ptersilie Oct 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thanks! With this comment and @ltratt's comment above, this makes a lot more sense now.

(1.0 >= 2) println.
(2.0 >= 0) println.

(1.0 <= 1) println.
(1.0 <= 2) println.
(2.0 <= 0) println.
)
)
29 changes: 29 additions & 0 deletions lang_tests/obj1.som
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"
VM:
status: success
stdout:
true
false
false
true
true
true
false
false
true
"

obj1 = (
run = (
(1 == 1) println.
(1 <> 1) println.
(1 ~= 1) println.
(1 <> 2) println.
(1 ~= 2) println.

(self == self) println.
(self <> self) println.
(self == 'a') println.
(self <> 'a') println.
)
)
22 changes: 22 additions & 0 deletions lang_tests/obj2.som
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"
VM:
status: success
stdout:
true
true
true
true
false
false
"

obj2 = (
run = (
(1 == 1) println.
(100 == 100) println.
((1 << 200) == (1 << 200)) println.
(1.0 == 1.0) println.
(1.0 == 1) println.
(1 == 1.0) println.
)
)
4 changes: 4 additions & 0 deletions lib/SOM/Double.som
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@ Double = (
* argument = primitive
= argument = primitive
< argument = primitive
> argument = ( ^(self >= argument) and: [ self <> argument ] )
>= argument = ( ^(self < argument) not )
<= argument = ( ^(self < argument) or: [ self = argument ] )
negative = ( ^self < 0.0 )
asString = primitive
)
2 changes: 2 additions & 0 deletions lib/SOM/False.som
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
False = Boolean (
asString = ( ^'false' )
not = ( ^true )
or: block = ( ^block value )
and: block = ( ^false )
ifTrue: block = ( ^nil )
ifFalse: block = ( ^block value )
)
5 changes: 5 additions & 0 deletions lib/SOM/Object.som
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ Object = nil (
class = primitive
asString = ( ^'instance of ' concatenate: (self class asString) )

= other = ( ^self == other )
<> argument = ( ^(self = argument) not )
== other = primitive
~= other = (^ (self == other) not )

print = ( self asString print )
println = (
self print.
Expand Down
2 changes: 2 additions & 0 deletions lib/SOM/True.som
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
True = Boolean (
asString = ( ^'true' )
not = ( ^false )
or: block = ( ^true )
and: block = ( ^block value )
ifTrue: block = ( ^block value )
ifFalse: block = ( ^nil )
)
4 changes: 4 additions & 0 deletions src/lib/compiler/ast_to_instrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ impl<'a> Compiler<'a> {
requires_args(1)?;
Ok(cobjects::MethodBody::Primitive(Primitive::Equals))
}
"==" => {
requires_args(1)?;
Ok(cobjects::MethodBody::Primitive(Primitive::RefEquals))
}
"~=" => {
requires_args(1)?;
Ok(cobjects::MethodBody::Primitive(Primitive::NotEquals))
Expand Down
1 change: 1 addition & 0 deletions src/lib/compiler/instrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub enum Primitive {
New,
PrintNewline,
PrintString,
RefEquals,
Restart,
Shl,
Sub,
Expand Down
4 changes: 4 additions & 0 deletions src/lib/vm/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,10 @@ impl VM {
self.stack_push(stry!(rcv.not_equals(self, self.stack_pop())));
SendReturn::Val
}
Primitive::RefEquals => {
self.stack_push(stry!(rcv.ref_equals(self, self.stack_pop())));
SendReturn::Val
}
Primitive::Restart => unreachable!(),
Primitive::PrintNewline => {
println!();
Expand Down
45 changes: 45 additions & 0 deletions src/lib/vm/objects/double.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,51 @@ impl Obj for Double {
}))
}
}

fn ref_equals(&self, vm: &VM, other: Val) -> Result<Val, Box<VMError>> {
let b = if let Some(rhs) = other.try_downcast::<Double>(vm) {
self.val == rhs.double()
} else {
false
};
Ok(Val::from_bool(vm, b))
}

fn equals(&self, vm: &VM, other: Val) -> Result<Val, Box<VMError>> {
let b = if let Some(rhs) = other.as_isize(vm) {
self.val == (rhs as f64)
} else if let Some(rhs) = other.try_downcast::<Double>(vm) {
self.val == rhs.double()
} else if let Some(rhs) = other.try_downcast::<ArbInt>(vm) {
match rhs.bigint().to_f64() {
Some(i) => self.val == i,
None => false,
}
} else {
false
};

Ok(Val::from_bool(vm, b))
}

fn less_than(&self, vm: &VM, other: Val) -> Result<Val, Box<VMError>> {
let b = if let Some(rhs) = other.as_isize(vm) {
self.val < (rhs as f64)
} else if let Some(rhs) = other.try_downcast::<Double>(vm) {
self.val < rhs.double()
} else if let Some(rhs) = other.try_downcast::<ArbInt>(vm) {
match rhs.bigint().to_f64() {
Some(i) => self.val < i,
None => false,
}
} else {
return Err(Box::new(VMError::NotANumber {
got: other.dyn_objtype(vm),
}));
};

Ok(Val::from_bool(vm, b))
}
}

impl StaticObjType for Double {
Expand Down
9 changes: 9 additions & 0 deletions src/lib/vm/objects/integers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ impl Obj for ArbInt {
}
}

fn ref_equals(&self, vm: &VM, other: Val) -> Result<Val, Box<VMError>> {
let b = if let Some(rhs) = other.try_downcast::<ArbInt>(vm) {
self.val == rhs.val
} else {
false
};
Ok(Val::from_bool(vm, b))
}

fn equals(&self, vm: &VM, other: Val) -> Result<Val, Box<VMError>> {
let b = if other.dyn_objtype(vm) == ObjType::Int {
debug_assert!(self.val != BigInt::from_isize(other.as_isize(vm).unwrap()).unwrap());
Expand Down
12 changes: 12 additions & 0 deletions src/lib/vm/objects/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ pub trait Obj: std::fmt::Debug + abgc::GcLayout {
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<Val, Box<VMError>> {
let other_tobj = other.tobj(vm)?;
let other_data =
unsafe { std::mem::transmute::<&dyn Obj, (*const u8, usize)>(&**other_tobj).0 };
Ok(Val::from_bool(
vm,
(self as *const _ as *const u8) == other_data,
))
}

/// Does this `Val` equal `other`?
fn equals(&self, _: &VM, _: Val) -> Result<Val, Box<VMError>> {
unimplemented!();
Expand Down
9 changes: 9 additions & 0 deletions src/lib/vm/val.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,15 @@ impl Val {
ValKind::GCBOX => self.tobj(vm).unwrap().to_strval(vm),
}
}

/// Is this `Val` reference equal to `other`? Notice that for integers (but not Doubles)
/// "reference equal" is equivalent to "equals".
pub fn ref_equals(&self, vm: &VM, other: Val) -> Result<Val, Box<VMError>> {
match self.valkind() {
ValKind::INT => self.equals(vm, other),
ValKind::GCBOX => self.tobj(vm)?.ref_equals(vm, other),
}
}
}

macro_rules! binop_all {
Expand Down