Implement in operator

This commit is contained in:
Andrew Morris
2023-07-06 15:56:04 +10:00
parent eb95deeb5d
commit 814fb09159
13 changed files with 208 additions and 34 deletions

View File

@@ -70,6 +70,13 @@ where
Ok(Self::bo_sub(&key.to_string()))
}
fn has(&self, key: &Val) -> Option<bool> {
match Self::bo_sub(&key.to_string()) {
Val::Undefined => Some(false),
_ => Some(true),
}
}
fn submov(&mut self, _key: &Val, _value: Val) -> Result<(), Val> {
Err(format!("Cannot assign to subscript of {} builtin", Self::bo_name()).to_type_error())
}

View File

@@ -92,6 +92,18 @@ impl ValTrait for Generator {
Ok(Val::Undefined)
}
fn has(&self, key: &Val) -> Option<bool> {
if key.to_string() == "next" {
return Some(true);
}
if let Val::Symbol(VsSymbol::ITERATOR) = key {
return Some(true);
}
Some(false)
}
fn submov(&mut self, _key: &Val, _value: Val) -> Result<(), Val> {
Err("Cannot assign to subscript of a generator".to_type_error())
}

View File

@@ -12,7 +12,9 @@ use crate::{
LoadFunctionResult, ValTrait,
};
use super::{iteration_result::IterationResult, return_this::RETURN_THIS};
use super::{
iteration_result::IterationResult, iterator_has::iterator_has, return_this::RETURN_THIS,
};
#[derive(Clone)]
pub struct ArrayEntriesIterator {
@@ -87,6 +89,10 @@ impl ValTrait for ArrayEntriesIterator {
Ok(Val::Undefined)
}
fn has(&self, key: &Val) -> Option<bool> {
iterator_has(key)
}
fn submov(&mut self, _key: &Val, _value: Val) -> Result<(), Val> {
Err("Cannot assign to subscript of array iterator".to_type_error())
}

View File

@@ -12,7 +12,9 @@ use crate::{
LoadFunctionResult, ValTrait,
};
use super::{iteration_result::IterationResult, return_this::RETURN_THIS};
use super::{
iteration_result::IterationResult, iterator_has::iterator_has, return_this::RETURN_THIS,
};
#[derive(Clone)]
pub struct ArrayIterator {
@@ -87,6 +89,10 @@ impl ValTrait for ArrayIterator {
Ok(Val::Undefined)
}
fn has(&self, key: &Val) -> Option<bool> {
iterator_has(key)
}
fn submov(&mut self, _key: &Val, _value: Val) -> Result<(), Val> {
Err("Cannot assign to subscript of array iterator".to_type_error())
}

View File

@@ -69,6 +69,13 @@ impl ValTrait for IterationResult {
})
}
fn has(&self, key: &Val) -> Option<bool> {
Some(match key.to_string().as_str() {
"value" | "done" => true,
_ => false,
})
}
fn submov(&mut self, _key: &Val, _value: Val) -> Result<(), Val> {
Err("Cannot assign to subscript of iteration result".to_type_error())
}

View File

@@ -0,0 +1,17 @@
use crate::{vs_value::Val, VsSymbol};
pub fn iterator_has(key: &Val) -> Option<bool> {
if key.to_string() == "next" {
return Some(true);
}
if let Val::Symbol(key) = key {
match key {
VsSymbol::ITERATOR => {
return Some(true);
}
}
}
Some(false)
}

View File

@@ -1,5 +1,6 @@
pub mod array_entries_iterator;
pub mod array_iterator;
pub mod iteration_result;
mod iterator_has;
pub mod return_this;
pub mod string_iterator;

View File

@@ -12,7 +12,9 @@ use crate::{
LoadFunctionResult, ValTrait,
};
use super::{iteration_result::IterationResult, return_this::RETURN_THIS};
use super::{
iteration_result::IterationResult, iterator_has::iterator_has, return_this::RETURN_THIS,
};
#[derive(Clone)]
pub struct StringIterator {
@@ -123,6 +125,10 @@ impl ValTrait for StringIterator {
Ok(Val::Undefined)
}
fn has(&self, key: &Val) -> Option<bool> {
iterator_has(key)
}
fn submov(&mut self, _key: &Val, _value: Val) -> Result<(), Val> {
Err("Cannot assign to subscript of string iterator".to_type_error())
}

View File

@@ -63,6 +63,10 @@ impl ValTrait for NativeFrameFunction {
Err("TODO: Subscript native function".to_internal_error())
}
fn has(&self, _key: &Val) -> Option<bool> {
Some(false)
}
fn submov(&mut self, _key: &Val, _value: Val) -> Result<(), Val> {
Err("Cannot assign to subscript of native function".to_type_error())
}

View File

@@ -84,6 +84,10 @@ impl ValTrait for NativeFunction {
Err("TODO: Subscript native function".to_internal_error())
}
fn has(&self, _key: &Val) -> Option<bool> {
Some(false)
}
fn submov(&mut self, _key: &Val, _value: Val) -> Result<(), Val> {
Err("Cannot assign to subscript of native function".to_type_error())
}

View File

@@ -1,5 +1,4 @@
use std::collections::BTreeMap;
use std::mem::take;
use std::rc::Rc;
use std::str::FromStr;
@@ -523,8 +522,11 @@ pub fn op_instance_of(_left: &Val, _right: &Val) -> Result<Val, Val> {
Err("TODO: op_instance_of".to_internal_error())
}
pub fn op_in(_left: &Val, _right: &Val) -> Result<Val, Val> {
Err("TODO: op_in".to_internal_error())
pub fn op_in(left: &Val, right: &Val) -> Result<Val, Val> {
match right.has(left) {
Some(found) => Ok(found.to_val()),
None => Err(format!("Can't use `in` with a {}", right.typeof_()).to_type_error()),
}
}
pub fn op_sub(left: &mut Val, right: &Val) -> Result<Val, Val> {
@@ -541,34 +543,7 @@ pub fn op_sub(left: &mut Val, right: &Val) -> Result<Val, Val> {
Val::BigInt(bigint) => Ok(op_sub_bigint(bigint, right)),
Val::Symbol(_) => Ok(Val::Undefined),
Val::String(string_data) => Ok(op_sub_string(string_data, right)),
Val::Array(array_data) => {
let right_index = match right.to_index() {
None => {
// FIXME: Inefficient to_string() that gets duplicated
// when subscripting the object
if right.to_string() == "length" {
return Ok(Val::Number(array_data.elements.len() as f64));
}
return op_sub_array(array_data, right);
}
Some(i) => i,
};
if right_index >= array_data.elements.len() {
return Ok(Val::Undefined);
}
let res = match Rc::get_mut(array_data) {
Some(array_data) => take(&mut array_data.elements[right_index]),
None => array_data.elements[right_index].clone(),
};
return Ok(match res {
Val::Void => Val::Undefined,
_ => res,
});
}
Val::Array(array_data) => op_sub_array(array_data, right),
Val::Object(object_data) => Ok(object_data.sub(right)), // TODO: move on single ref
Val::Function(_) => Ok(Val::Undefined),
Val::Class(class) => op_sub(&mut class.static_.clone(), right),

View File

@@ -1,5 +1,6 @@
use core::fmt;
use std::any::Any;
use std::fmt::Display;
use std::rc::Rc;
use std::str::FromStr;
@@ -57,6 +58,24 @@ pub enum VsType {
Class,
}
impl Display for VsType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
VsType::Undefined => f.write_str("undefined"),
VsType::Null => f.write_str("null"),
VsType::Bool => f.write_str("bool"),
VsType::Number => f.write_str("number"),
VsType::BigInt => f.write_str("bigint"),
VsType::Symbol => f.write_str("symbol"),
VsType::String => f.write_str("string"),
VsType::Array => f.write_str("array"),
VsType::Object => f.write_str("object"),
VsType::Function => f.write_str("function"),
VsType::Class => f.write_str("class"),
}
}
}
pub enum LoadFunctionResult {
NotAFunction,
StackFrame(StackFrame),
@@ -80,6 +99,7 @@ pub trait ValTrait: fmt::Display {
fn load_function(&self) -> LoadFunctionResult;
fn sub(&self, key: &Val) -> Result<Val, Val>;
fn has(&self, key: &Val) -> Option<bool>;
fn submov(&mut self, key: &Val, value: Val) -> Result<(), Val>;
fn pretty_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
@@ -355,6 +375,97 @@ impl ValTrait for Val {
op_sub(&mut self.clone(), key)
}
fn has(&self, key: &Val) -> Option<bool> {
match self {
Val::Void
| Val::Undefined
| Val::Null
| Val::Bool(_)
| Val::Number(_)
| Val::BigInt(_)
| Val::Symbol(_)
| Val::String(_) => None,
Val::Array(array) => {
let index = match key.to_index() {
None => {
return Some(match key.to_string().as_str() {
"at" => true,
"concat" => true,
"copyWithin" => true,
"entries" => true,
"every" => true,
"fill" => true,
"filter" => true,
"find" => true,
"findIndex" => true,
"flat" => true,
"flatMap" => true,
"includes" => true,
"indexOf" => true,
"join" => true,
"keys" => true,
"lastIndexOf" => true,
"length" => true,
"map" => true,
"pop" => true,
"push" => true,
"reduce" => true,
"reduceRight" => true,
"reverse" => true,
"shift" => true,
"slice" => true,
"some" => true,
"sort" => true,
"splice" => true,
"toLocaleString" => true,
"toString" => true,
"unshift" => true,
"values" => true,
_ => false,
});
}
Some(i) => i,
};
return Some(index < array.elements.len());
}
Val::Object(object) => match key {
Val::Symbol(symbol) => {
if object.symbol_map.contains_key(symbol) {
return Some(true);
}
if let Some(proto) = &object.prototype {
return proto.has(key);
}
return Some(false);
}
_ => {
if object.string_map.contains_key(&key.to_string()) {
return Some(true);
}
if let Some(proto) = &object.prototype {
return proto.has(key);
}
return Some(false);
}
},
Val::Function(_) => Some(false),
Val::Class(class) => class.static_.has(key),
Val::Static(static_) => static_.has(key),
Val::Dynamic(dynamic) => dynamic.has(key),
Val::CopyCounter(_) => Some(match key.to_string().as_str() {
"tag" | "count" => true,
_ => false,
}),
}
}
fn submov(&mut self, key: &Val, value: Val) -> Result<(), Val> {
op_submov(self, key, value)
}