Implement direct class comparison

This commit is contained in:
Andrew Morris
2023-08-16 15:30:25 +10:00
parent 5d1da13903
commit d49937663c
12 changed files with 75 additions and 30 deletions

View File

@@ -40,6 +40,8 @@ impl BuiltinObject for ErrorBuiltin {
fn bo_as_class_data() -> Option<Rc<VsClass>> {
Some(Rc::new(VsClass {
name: "Error".to_string(),
content_hash: None,
constructor: SET_MESSAGE.to_val(),
prototype: make_error_prototype(),
static_: VsObject::default().to_val(),

View File

@@ -39,6 +39,8 @@ impl BuiltinObject for InternalErrorBuiltin {
fn bo_as_class_data() -> Option<Rc<VsClass>> {
Some(Rc::new(VsClass {
name: "InternalError".to_string(),
content_hash: None,
constructor: Val::Static(&SET_MESSAGE),
prototype: make_internal_error_prototype(),
static_: VsObject::default().to_val(),

View File

@@ -31,6 +31,8 @@ impl BuiltinObject for RangeErrorBuiltin {
fn bo_as_class_data() -> Option<Rc<VsClass>> {
Some(Rc::new(VsClass {
name: "RangeError".to_string(),
content_hash: None,
constructor: Val::Static(&SET_MESSAGE),
prototype: make_range_error_prototype(),
static_: VsObject::default().to_val(),

View File

@@ -39,6 +39,8 @@ impl BuiltinObject for TypeErrorBuiltin {
fn bo_as_class_data() -> Option<Rc<VsClass>> {
Some(Rc::new(VsClass {
name: "TypeError".to_string(),
content_hash: None,
constructor: Val::Static(&SET_MESSAGE),
prototype: make_type_error_prototype(),
static_: VsObject::default().to_val(),

View File

@@ -6,7 +6,6 @@ use num_bigint::BigInt;
use num_bigint::Sign;
use valuescript_common::InstructionByte;
use crate::builtins::internal_error_builtin::ToInternalError;
use crate::builtins::BUILTIN_VALS;
use crate::bytecode::Bytecode;
use crate::vs_class::VsClass;
@@ -147,12 +146,18 @@ impl BytecodeDecoder {
val => take(val),
},
BytecodeType::Builtin => BUILTIN_VALS[self.decode_varsize_uint()](),
BytecodeType::Class => VsClass {
constructor: self.decode_val(registers),
prototype: self.decode_val(registers),
static_: self.decode_val(registers),
BytecodeType::Class => {
let meta = self.decode_meta();
VsClass {
name: meta.name,
content_hash: meta.content_hash,
constructor: self.decode_val(registers),
prototype: self.decode_val(registers),
static_: self.decode_val(registers),
}
.to_val()
}
.to_val(),
BytecodeType::BigInt => self.decode_bigint().to_val(),
BytecodeType::GeneratorFunction => self.decode_function(true),
BytecodeType::Unrecognized => panic!("Unrecognized bytecode type at {}", self.pos - 1),
@@ -314,20 +319,19 @@ impl BytecodeDecoder {
InstructionByte::from_byte(self.decode_byte())
}
pub fn decode_content_hash(&mut self) -> Result<[u8; 32], Val> {
pub fn decode_meta(&mut self) -> Meta {
if self.decode_byte() != 0x16 {
return Err("Can't decode a content hash here".to_internal_error());
panic!("Expected meta");
}
if self.decode_type() != BytecodeType::String {
return Err("Expected string".to_internal_error());
panic!("Expected string");
}
let name_len = self.decode_varsize_uint();
self.pos += name_len;
let name = self.decode_string();
match self.decode_byte() {
0 | 1 => Err("Missing content hash".to_internal_error()), // Empty | Src
let content_hash = match self.decode_byte() {
0 | 1 => None, // Empty | Src
2 => {
// Hash
let mut res = [0u8; 32];
@@ -336,9 +340,16 @@ impl BytecodeDecoder {
*b = self.decode_byte();
}
Ok(res)
Some(res)
}
_ => Err("Unrecognized content_hashable case".to_internal_error()),
}
_ => panic!("Unrecognized ContentHashable case"),
};
Meta { name, content_hash }
}
}
pub struct Meta {
pub name: String,
pub content_hash: Option<[u8; 32]>,
}

View File

@@ -205,6 +205,11 @@ pub fn op_eq_impl(left: &Val, right: &Val) -> Result<bool, Val> {
true
}
(Val::Class(left), Val::Class(right)) => match (&left.content_hash, &right.content_hash) {
(None, None) => std::ptr::eq(&**left, &**right),
(None, Some(_)) | (Some(_), None) => return Ok(false),
(Some(left_hash), Some(right_hash)) => left_hash == right_hash,
},
_ => {
if left.is_truthy() != right.is_truthy() {
return Ok(false);
@@ -350,6 +355,11 @@ pub fn op_triple_eq_impl(left: &Val, right: &Val) -> Result<bool, Val> {
format!("TODO: op=== with special types ({}, {})", left, right).to_internal_error(),
);
}
(Val::Class(left), Val::Class(right)) => match (&left.content_hash, &right.content_hash) {
(None, None) => std::ptr::eq(&**left, &**right),
(None, Some(_)) | (Some(_), None) => return Ok(false),
(Some(left_hash), Some(right_hash)) => left_hash == right_hash,
},
_ => {
assert!(left.typeof_() != right.typeof_());
false

View File

@@ -6,6 +6,8 @@ use super::vs_value::Val;
#[derive(Debug)]
pub struct VsClass {
pub name: String,
pub content_hash: Option<[u8; 32]>,
pub constructor: Val,
pub prototype: Val,
pub static_: Val,

View File

@@ -42,7 +42,10 @@ impl VsFunction {
pub fn content_hash(&self) -> Result<[u8; 32], Val> {
match self.meta_pos {
Some(p) => self.bytecode.decoder(p).decode_content_hash(),
Some(p) => match self.bytecode.decoder(p).decode_meta().content_hash {
Some(content_hash) => Ok(content_hash),
None => Err("content_hash missing".to_internal_error()),
},
None => Err("Can't get content_hash without meta_pos".to_internal_error()),
}
}