Refactor Val to an enum

This commit is contained in:
Andrew Morris
2022-05-03 21:04:36 +10:00
parent fd71d6f08c
commit aa3f18ed20
12 changed files with 178 additions and 281 deletions

View File

@@ -1,10 +1,6 @@
use std::rc::Rc;
use super::vs_value::Val;
use super::vs_undefined::VsUndefined;
use super::vs_null::VsNull;
use super::vs_number::VsNumber;
use super::vs_string::VsString;
use super::vs_pointer::VsPointer;
use super::vs_function::VsFunction;
use super::instruction::Instruction;
@@ -83,19 +79,19 @@ impl BytecodeDecoder {
return match self.decode_type() {
End => std::panic!("Cannot decode end"),
Undefined => VsUndefined::new(),
Null => VsNull::new(),
False => std::panic!("Not implemented"),
True => std::panic!("Not implemented"),
SignedByte => VsNumber::from_f64(
Undefined => Val::Undefined,
Null => Val::Null,
False => Val::Bool(false),
True => Val::Bool(true),
SignedByte => Val::Number(
self.decode_signed_byte() as f64
),
Number => VsNumber::from_f64(
Number => Val::Number(
self.decode_number()
),
String => VsString::from_string(
String => Val::String(Rc::new(
self.decode_string()
),
)),
Array => std::panic!("Not implemented"),
Object => std::panic!("Not implemented"),
Function => self.decode_function_header(),
@@ -184,12 +180,12 @@ impl BytecodeDecoder {
let register_count = self.decode_byte() as usize;
let parameter_count = self.decode_byte() as usize;
return Rc::new(VsFunction {
return Val::Function(Rc::new(VsFunction {
bytecode: self.data.clone(),
register_count: register_count,
parameter_count: parameter_count,
start: self.pos,
});
}));
}
pub fn decode_instruction(&mut self) -> Instruction {

View File

@@ -1,9 +1,4 @@
mod vs_value;
mod vs_undefined;
mod vs_null;
mod vs_bool;
mod vs_number;
mod vs_string;
mod vs_function;
mod vs_pointer;
mod operations;

View File

@@ -1,31 +1,30 @@
use std::rc::Rc;
use super::vs_value::Val;
use super::vs_value::ValTrait;
use super::vs_value::VsType;
use super::vs_string::VsString;
use super::vs_number::VsNumber;
use super::vs_bool::VsBool;
pub fn op_plus(left: &Val, right: &Val) -> Val {
let left_prim = left.to_primitive();
let right_prim = right.to_primitive();
if left_prim.typeof_() == VsType::String || right_prim.typeof_() == VsType::String {
return VsString::from_string(left_prim.to_string() + &right_prim.to_string());
return Val::String(Rc::new(left_prim.val_to_string() + &right_prim.val_to_string()));
}
return VsNumber::from_f64(left_prim.to_number() + right_prim.to_number());
return Val::Number(left_prim.to_number() + right_prim.to_number());
}
pub fn op_minus(left: &Val, right: &Val) -> Val {
return VsNumber::from_f64(left.to_number() - right.to_number());
return Val::Number(left.to_number() - right.to_number());
}
pub fn op_mul(left: &Val, right: &Val) -> Val {
return VsNumber::from_f64(left.to_number() * right.to_number());
return Val::Number(left.to_number() * right.to_number());
}
pub fn op_mod(left: &Val, right: &Val) -> Val {
return VsNumber::from_f64(left.to_number() % right.to_number());
return Val::Number(left.to_number() % right.to_number());
}
pub fn op_less(left: &Val, right: &Val) -> Val {
@@ -33,7 +32,7 @@ pub fn op_less(left: &Val, right: &Val) -> Val {
std::panic!("Not implemented");
}
return VsBool::from_bool(left.to_number() < right.to_number());
return Val::Bool(left.to_number() < right.to_number());
}
pub fn op_triple_ne(left: &Val, right: &Val) -> Val {
@@ -41,5 +40,5 @@ pub fn op_triple_ne(left: &Val, right: &Val) -> Val {
std::panic!("Not implemented");
}
return VsBool::from_bool(left.to_number() != right.to_number());
return Val::Bool(left.to_number() != right.to_number());
}

View File

@@ -1,8 +1,7 @@
use std::rc::Rc;
use super::vs_value::Val;
use super::vs_undefined::VsUndefined;
use super::vs_number::VsNumber;
use super::vs_value::ValTrait;
use super::operations;
use super::bytecode_decoder::BytecodeDecoder;
use super::bytecode_decoder::BytecodeType;
@@ -48,8 +47,8 @@ impl VirtualMachine {
};
let mut registers: Vec<Val> = Vec::with_capacity(2);
registers.push(VsUndefined::new());
registers.push(VsUndefined::new());
registers.push(Val::Undefined);
registers.push(Val::Undefined);
let frame = StackFrame {
decoder: BytecodeDecoder {
@@ -88,7 +87,7 @@ impl VirtualMachine {
OpInc => {
let register_index = frame.decoder.decode_register_index().unwrap();
let mut val = frame.registers[register_index].clone();
val = operations::op_plus(&val, &VsNumber::from_f64(1_f64));
val = operations::op_plus(&val, &Val::Number(1_f64));
frame.registers[register_index] = val;
},

View File

@@ -1,42 +0,0 @@
use std::rc::Rc;
use super::vs_value::Val;
use super::vs_value::VsType;
use super::vs_value::VsValue;
use super::virtual_machine::StackFrame;
pub struct VsBool {
value: bool,
}
impl VsBool {
pub fn from_bool(value: bool) -> Val {
return Rc::new(VsBool { value: value });
}
}
impl VsValue for VsBool {
fn typeof_(&self) -> VsType {
return VsType::Bool;
}
fn to_string(&self) -> String {
return self.value.to_string();
}
fn to_number(&self) -> f64 {
return if self.value { 1_f64 } else { 0_f64 };
}
fn is_primitive(&self) -> bool {
return true;
}
fn make_frame(&self) -> Option<StackFrame> {
return None;
}
fn is_truthy(&self) -> bool {
return self.value;
}
}

View File

@@ -1,9 +1,8 @@
use std::rc::Rc;
use super::vs_value::VsType;
use super::vs_value::VsValue;
use super::vs_value::Val;
use super::vs_undefined::VsUndefined;
use super::vs_value::ValTrait;
use super::virtual_machine::StackFrame;
use super::bytecode_decoder::BytecodeDecoder;
@@ -14,12 +13,12 @@ pub struct VsFunction {
pub start: usize,
}
impl VsValue for VsFunction {
impl ValTrait for VsFunction {
fn typeof_(&self) -> VsType {
return VsType::Function;
}
fn to_string(&self) -> String {
fn val_to_string(&self) -> String {
return "[function]".to_string();
}
@@ -31,11 +30,15 @@ impl VsValue for VsFunction {
return false;
}
fn to_primitive(&self) -> Val {
return Val::String(Rc::new(self.val_to_string()));
}
fn make_frame(&self) -> Option<StackFrame> {
let mut registers: Vec<Val> = Vec::with_capacity(self.register_count - 1);
for _ in 0..(self.register_count - 1) {
registers.push(VsUndefined::new());
registers.push(Val::Undefined);
}
return Some(StackFrame {

View File

@@ -1,40 +0,0 @@
use std::rc::Rc;
use super::vs_value::Val;
use super::vs_value::VsType;
use super::vs_value::VsValue;
use super::virtual_machine::StackFrame;
pub struct VsNull {}
impl VsNull {
pub fn new() -> Val {
return Rc::new(VsNull {});
}
}
impl VsValue for VsNull {
fn typeof_(&self) -> VsType {
return VsType::Null;
}
fn to_string(&self) -> String {
return "null".to_string();
}
fn to_number(&self) -> f64 {
return 0_f64;
}
fn is_primitive(&self) -> bool {
return true;
}
fn make_frame(&self) -> Option<StackFrame> {
return None;
}
fn is_truthy(&self) -> bool {
return false;
}
}

View File

@@ -1,42 +0,0 @@
use std::rc::Rc;
use super::vs_value::Val;
use super::vs_value::VsType;
use super::vs_value::VsValue;
use super::virtual_machine::StackFrame;
pub struct VsNumber {
value: f64,
}
impl VsNumber {
pub fn from_f64(value: f64) -> Val {
return Rc::new(VsNumber { value: value });
}
}
impl VsValue for VsNumber {
fn typeof_(&self) -> VsType {
return VsType::Number;
}
fn to_string(&self) -> String {
return self.value.to_string();
}
fn to_number(&self) -> f64 {
return self.value;
}
fn is_primitive(&self) -> bool {
return true;
}
fn make_frame(&self) -> Option<StackFrame> {
return None;
}
fn is_truthy(&self) -> bool {
return self.value != 0_f64;
}
}

View File

@@ -2,7 +2,7 @@ use std::rc::Rc;
use std::cell::RefCell;
use super::vs_value::Val;
use super::vs_value::VsValue;
use super::vs_value::ValTrait;
use super::vs_value::VsType;
use super::virtual_machine::StackFrame;
use super::bytecode_decoder::BytecodeDecoder;
@@ -16,11 +16,11 @@ pub struct VsPointer {
impl VsPointer {
pub fn new(bytecode: &Rc<Vec<u8>>, pos: usize) -> Val {
return Rc::new(VsPointer {
return Val::Custom(Rc::new(VsPointer {
bytecode: bytecode.clone(),
pos: pos,
decoded: RefCell::new(None),
});
}));
}
pub fn decode(&self) -> Val {
@@ -45,7 +45,7 @@ impl VsPointer {
}
}
impl VsValue for VsPointer {
impl ValTrait for VsPointer {
fn typeof_(&self) -> VsType {
let mut bd = BytecodeDecoder {
data: self.bytecode.clone(),
@@ -70,8 +70,8 @@ impl VsValue for VsPointer {
}
}
fn to_string(&self) -> String {
return self.decode().to_string();
fn val_to_string(&self) -> String {
return self.decode().val_to_string();
}
fn to_number(&self) -> f64 {
@@ -91,6 +91,10 @@ impl VsValue for VsPointer {
}
}
fn to_primitive(&self) -> Val {
return self.decode().to_primitive();
}
fn make_frame(&self) -> Option<StackFrame> {
return self.decode().make_frame();
}

View File

@@ -1,46 +0,0 @@
use std::rc::Rc;
use super::vs_value::Val;
use super::vs_value::VsType;
use super::vs_value::VsValue;
use super::virtual_machine::StackFrame;
pub struct VsString {
value: String,
}
impl VsString {
pub fn from_str(value: &str) -> Val {
return Rc::new(VsString { value: value.to_string() });
}
pub fn from_string(value: String) -> Val {
return Rc::new(VsString { value: value });
}
}
impl VsValue for VsString {
fn typeof_(&self) -> VsType {
return VsType::String;
}
fn to_string(&self) -> String {
return self.value.clone();
}
fn to_number(&self) -> f64 {
std::panic!("not implemented");
}
fn is_primitive(&self) -> bool {
return true;
}
fn make_frame(&self) -> Option<StackFrame> {
return None;
}
fn is_truthy(&self) -> bool {
return self.value != "";
}
}

View File

@@ -1,40 +0,0 @@
use std::rc::Rc;
use super::vs_value::Val;
use super::vs_value::VsType;
use super::vs_value::VsValue;
use super::virtual_machine::StackFrame;
pub struct VsUndefined {}
impl VsUndefined {
pub fn new() -> Val {
return Rc::new(VsUndefined {});
}
}
impl VsValue for VsUndefined {
fn typeof_(&self) -> VsType {
return VsType::Undefined;
}
fn to_string(&self) -> String {
return "undefined".to_string();
}
fn to_number(&self) -> f64 {
return f64::NAN;
}
fn is_primitive(&self) -> bool {
return true;
}
fn make_frame(&self) -> Option<StackFrame> {
return None;
}
fn is_truthy(&self) -> bool {
return false;
}
}

View File

@@ -1,9 +1,23 @@
use std::rc::Rc;
use std::collections::BTreeMap;
use std::str::FromStr;
use super::vs_string::VsString;
use super::vs_function::VsFunction;
use super::virtual_machine::StackFrame;
pub type Val = Rc<dyn VsValue>;
#[derive(Clone)]
pub enum Val {
Void,
Undefined,
Null,
Bool(bool),
Number(f64),
String(Rc<String>),
Array(Rc<Vec<Val>>),
Object(Rc<BTreeMap<String, Val>>),
Function(Rc<VsFunction>),
Custom(Rc<dyn ValTrait>),
}
#[derive(PartialEq)]
pub enum VsType {
@@ -17,47 +31,144 @@ pub enum VsType {
Function,
}
impl VsType {
pub fn as_val(&self) -> Val {
return VsString::from_str(match self {
Undefined => "undefined",
Null => "object",
Bool => "boolean",
Number => "number",
String => "string",
Array => "object",
Object => "object",
Function => "function",
});
}
}
pub trait VsValue {
pub trait ValTrait {
fn typeof_(&self) -> VsType;
fn to_string(&self) -> String;
fn val_to_string(&self) -> String;
fn to_number(&self) -> f64;
fn is_primitive(&self) -> bool;
fn to_primitive(&self) -> Val;
fn is_truthy(&self) -> bool;
fn make_frame(&self) -> Option<StackFrame>;
}
pub trait ValTrait {
fn to_primitive(&self) -> Val;
}
impl ValTrait for Val {
fn typeof_(&self) -> VsType {
use Val::*;
return match self {
Void => VsType::Undefined,
Undefined => VsType::Undefined,
Null => VsType::Null,
Bool(_) => VsType::Bool,
Number(_) => VsType::Number,
String(_) => VsType::String,
Array(_) => VsType::Array,
Object(_) => VsType::Object,
Function(_) => VsType::Function,
Custom(val) => val.typeof_(),
};
}
fn val_to_string(&self) -> String {
use Val::*;
return match self {
Void => "undefined".to_string(),
Undefined => "undefined".to_string(),
Null => "null".to_string(),
Bool(b) => b.to_string(),
Number(x) => x.to_string(), // TODO: Match js's number string format
String(s) => s.to_string(),
Array(vals) => {
if vals.len() == 0 {
"".to_string()
} else if vals.len() == 1 {
vals[0].val_to_string()
} else {
let mut iter = vals.iter();
let mut res = iter.next().unwrap().val_to_string();
for val in iter {
res += ",";
res += val.val_to_string().as_str();
}
res
}
},
Object(_) => "[object Object]".to_string(),
Function(_) => "[function]".to_string(),
Custom(val) => val.val_to_string(),
};
}
fn to_number(&self) -> f64 {
use Val::*;
return match self {
Void => f64::NAN,
Undefined => f64::NAN,
Null => 0_f64,
Bool(b) => *b as u8 as f64,
Number(x) => *x,
String(s) => f64::from_str(s).unwrap_or(f64::NAN),
Array(vals) => match vals.len() {
0 => 0_f64,
1 => vals[0].to_number(),
_ => f64::NAN,
},
Object(_) => f64::NAN,
Function(_) => f64::NAN,
Custom(val) => val.to_number(),
};
}
fn is_primitive(&self) -> bool {
use Val::*;
return match self {
Void => true,
Undefined => true,
Null => true,
Bool(_) => true,
Number(_) => true,
String(_) => true,
Array(_) => false,
Object(_) => false,
Function(_) => false,
Custom(val) => val.is_primitive(),
}
}
fn to_primitive(&self) -> Val {
if self.is_primitive() {
return self.clone();
}
return VsString::from_string(self.to_string());
return Val::String(Rc::new(self.val_to_string()));
}
fn is_truthy(&self) -> bool {
use Val::*;
return match self {
Void => false,
Undefined => false,
Null => false,
Bool(b) => *b,
Number(x) => *x != 0_f64,
String(s) => s.len() > 0,
Array(_) => true,
Object(_) => true,
Function(_) => true,
Custom(val) => val.is_truthy(),
}
}
fn make_frame(&self) -> Option<StackFrame> {
use Val::*;
return match self {
Function(f) => f.make_frame(),
Custom(val) => val.make_frame(),
_ => None,
}
}
}
impl std::fmt::Display for dyn VsValue {
impl std::fmt::Display for Val {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_string())
write!(f, "{}", self.val_to_string())
}
}