Skip to content

Commit

Permalink
Add reference equality.
Browse files Browse the repository at this point in the history
This is roughly equivalent to the `is` operator in Python in that it checks
normal objects for pointer equality, but numbers are checked for value equality.
Note that SOM (or, at least, java-som) doesn't define/implement the latter cases
properly yet (see SOM-st/SOM#23) so this commit makes
us diverge slightly.
  • Loading branch information
ltratt committed Sep 28, 2019
1 parent 3589ddd commit 86894f8
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 0 deletions.
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.
)
)
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
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 @@ -48,6 +48,7 @@ pub enum Primitive {
New,
PrintNewline,
PrintString,
RefEquals,
Restart,
Shl,
Sub,
Expand Down
30 changes: 30 additions & 0 deletions src/lib/vm/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ pub trait Obj: 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) -> ValResult {
let other_tobj = rtry!(other.tobj(vm));
let other_data =
unsafe { std::mem::transmute::<&dyn Obj, (*const u8, usize)>(&**other_tobj).0 };
ValResult::from_val(Val::from_bool(
vm,
(self as *const _ as *const u8) == other_data,
))
}

/// Does this `Val` equal `other`?
fn equals(&self, _: &VM, _: Val) -> ValResult {
unimplemented!();
Expand Down Expand Up @@ -395,6 +407,15 @@ impl Obj for Double {
})
}
}

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

impl StaticObjType for Double {
Expand Down Expand Up @@ -661,6 +682,15 @@ impl Obj for ArbInt {
}
}

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

fn equals(&self, vm: &VM, other: Val) -> ValResult {
let b = if other.dyn_objtype(vm) == ObjType::Int {
debug_assert!(self.val != BigInt::from_isize(other.as_isize(vm).unwrap()).unwrap());
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 @@ -426,6 +426,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) -> ValResult {
match self.valkind() {
ValKind::INT => self.equals(vm, other),
ValKind::GCBOX => rtry!(self.tobj(vm)).ref_equals(vm, other),
}
}
}

macro_rules! binop_all {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/vm/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ impl VM {
debug_assert_eq!(args.len(), 1);
rcv.not_equals(self, args[0].clone())
}
Primitive::RefEquals => {
debug_assert_eq!(args.len(), 1);
rcv.ref_equals(self, args[0].clone())
}
Primitive::Restart => {
// This is handled directly by exec_user.
ValResult::from_vmerror(VMError::PrimitiveError)
Expand Down

0 comments on commit 86894f8

Please sign in to comment.