mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-01-11 06:27:56 -05:00
wip
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2243,6 +2243,7 @@ dependencies = [
|
||||
"swc_ecma_ast",
|
||||
"swc_ecma_parser",
|
||||
"valuescript_common",
|
||||
"valuescript_vm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -18,3 +18,4 @@ swc_ecma_ast = "0.76.0"
|
||||
queues = "1.0.2"
|
||||
|
||||
valuescript_common = { path = "../valuescript_common" }
|
||||
valuescript_vm = { path = "../valuescript_vm" }
|
||||
|
||||
@@ -30,5 +30,6 @@ pub use gather_modules::gather_modules;
|
||||
pub use link_module::link_module;
|
||||
pub use module_compiler::compile_module;
|
||||
pub use module_compiler::CompilerOutput;
|
||||
pub use optimization::try_to_val::TryToVal;
|
||||
pub use resolve_path::resolve_path;
|
||||
pub use resolve_path::ResolvedPath;
|
||||
|
||||
@@ -3,5 +3,7 @@ mod extract_constants;
|
||||
mod optimize;
|
||||
mod shake_tree;
|
||||
mod simplify;
|
||||
pub mod try_to_val;
|
||||
pub mod try_to_value;
|
||||
|
||||
pub use optimize::optimize;
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
use crate::asm::{DefinitionContent, FnLine, Function, Instruction, Module};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use valuescript_vm::{operations, vs_value::Val};
|
||||
|
||||
use crate::{
|
||||
asm::{DefinitionContent, FnLine, Function, Instruction, Module, Number, Register, Value},
|
||||
TryToVal,
|
||||
};
|
||||
|
||||
use super::try_to_value::TryToValue;
|
||||
|
||||
pub fn simplify(module: &mut Module) {
|
||||
for defn in &mut module.definitions {
|
||||
@@ -14,7 +24,7 @@ pub fn simplify(module: &mut Module) {
|
||||
#[derive(Default)]
|
||||
struct FnState {
|
||||
mutable_this_established: bool,
|
||||
// registers: HashMap<Register, Value>,
|
||||
registers: HashMap<Register, Value>,
|
||||
}
|
||||
|
||||
impl FnState {
|
||||
@@ -24,28 +34,333 @@ impl FnState {
|
||||
|
||||
fn simplify_line(&self, line: &mut FnLine) {
|
||||
match line {
|
||||
FnLine::Instruction(instr) => {
|
||||
if let Instruction::RequireMutableThis = instr {
|
||||
FnLine::Instruction(instr) => match instr {
|
||||
Instruction::End => {}
|
||||
Instruction::Mov(a1, _) => {
|
||||
self.simplify_arg(a1);
|
||||
}
|
||||
|
||||
Instruction::OpInc(_) => {}
|
||||
Instruction::OpDec(_) => {}
|
||||
|
||||
Instruction::OpNot(a1, _)
|
||||
| Instruction::OpBitNot(a1, _)
|
||||
| Instruction::TypeOf(a1, _)
|
||||
| Instruction::UnaryPlus(a1, _)
|
||||
| Instruction::UnaryMinus(a1, _)
|
||||
| Instruction::Throw(a1)
|
||||
| Instruction::Import(a1, _)
|
||||
| Instruction::ImportStar(a1, _)
|
||||
| Instruction::Cat(a1, _)
|
||||
| Instruction::Yield(a1, _)
|
||||
| Instruction::YieldStar(a1, _) => {
|
||||
self.simplify_arg(a1);
|
||||
}
|
||||
|
||||
Instruction::OpPlus(a1, a2, _)
|
||||
| Instruction::OpMinus(a1, a2, _)
|
||||
| Instruction::OpMul(a1, a2, _)
|
||||
| Instruction::OpDiv(a1, a2, _)
|
||||
| Instruction::OpMod(a1, a2, _)
|
||||
| Instruction::OpExp(a1, a2, _)
|
||||
| Instruction::OpEq(a1, a2, _)
|
||||
| Instruction::OpNe(a1, a2, _)
|
||||
| Instruction::OpTripleEq(a1, a2, _)
|
||||
| Instruction::OpTripleNe(a1, a2, _)
|
||||
| Instruction::OpAnd(a1, a2, _)
|
||||
| Instruction::OpOr(a1, a2, _)
|
||||
| Instruction::OpLess(a1, a2, _)
|
||||
| Instruction::OpLessEq(a1, a2, _)
|
||||
| Instruction::OpGreater(a1, a2, _)
|
||||
| Instruction::OpGreaterEq(a1, a2, _)
|
||||
| Instruction::OpNullishCoalesce(a1, a2, _)
|
||||
| Instruction::OpOptionalChain(a1, a2, _)
|
||||
| Instruction::OpBitAnd(a1, a2, _)
|
||||
| Instruction::OpBitOr(a1, a2, _)
|
||||
| Instruction::OpBitXor(a1, a2, _)
|
||||
| Instruction::OpLeftShift(a1, a2, _)
|
||||
| Instruction::OpRightShift(a1, a2, _)
|
||||
| Instruction::OpRightShiftUnsigned(a1, a2, _)
|
||||
| Instruction::InstanceOf(a1, a2, _)
|
||||
| Instruction::In(a1, a2, _)
|
||||
| Instruction::Call(a1, a2, _)
|
||||
| Instruction::Bind(a1, a2, _)
|
||||
| Instruction::Sub(a1, a2, _)
|
||||
| Instruction::SubMov(a1, a2, _)
|
||||
| Instruction::New(a1, a2, _) => {
|
||||
self.simplify_arg(a1);
|
||||
self.simplify_arg(a2);
|
||||
}
|
||||
|
||||
Instruction::Apply(a1, _this, a3, _) => {
|
||||
self.simplify_arg(a1);
|
||||
self.simplify_arg(a3);
|
||||
}
|
||||
|
||||
Instruction::SubCall(_this, a2, a3, _) | Instruction::ThisSubCall(_this, a2, a3, _) => {
|
||||
self.simplify_arg(a2);
|
||||
self.simplify_arg(a3);
|
||||
}
|
||||
|
||||
Instruction::ConstSubCall(a1, a2, a3, _) => {
|
||||
self.simplify_arg(a1);
|
||||
self.simplify_arg(a2);
|
||||
self.simplify_arg(a3);
|
||||
}
|
||||
|
||||
Instruction::JmpIf(a1, _) => {
|
||||
self.simplify_arg(a1);
|
||||
}
|
||||
|
||||
Instruction::Jmp(_) => {}
|
||||
Instruction::SetCatch(_, _) => {}
|
||||
Instruction::UnsetCatch => {}
|
||||
Instruction::RequireMutableThis => {
|
||||
if self.mutable_this_established {
|
||||
*line = FnLine::Comment(line.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
Instruction::Next(_, _) => {}
|
||||
Instruction::UnpackIterRes(_, _, _) => {}
|
||||
},
|
||||
FnLine::Label(..) | FnLine::Empty | FnLine::Comment(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_line(&mut self, line: &FnLine) {
|
||||
match line {
|
||||
FnLine::Instruction(instr) => {
|
||||
if let Instruction::RequireMutableThis = instr {
|
||||
self.mutable_this_established = true;
|
||||
fn simplify_arg(&self, arg: &mut Value) {
|
||||
arg.visit_values_mut(&mut |value| {
|
||||
if let Value::Register(reg) = value {
|
||||
if let Some(new_value) = self.registers.get(reg) {
|
||||
*value = new_value.clone();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn apply_line(&mut self, line: &FnLine) {
|
||||
match line {
|
||||
FnLine::Instruction(instr) => match instr {
|
||||
Instruction::End => {}
|
||||
Instruction::Mov(a1, dst) => {
|
||||
self.set_register(dst, Some(a1.clone()));
|
||||
}
|
||||
|
||||
Instruction::OpInc(reg) => {
|
||||
// TODO: Use apply_binary_op?
|
||||
|
||||
let new_value = match self.registers.get(reg) {
|
||||
Some(Value::Number(Number(x))) => Some(Value::Number(Number(x + 1.0))),
|
||||
Some(Value::BigInt(x)) => Some(Value::BigInt(x + BigInt::from(1))),
|
||||
Some(_) => None,
|
||||
None => return,
|
||||
};
|
||||
|
||||
self.set_register(reg, new_value);
|
||||
}
|
||||
Instruction::OpDec(reg) => {
|
||||
let new_value = match self.registers.get(reg) {
|
||||
Some(Value::Number(Number(x))) => Some(Value::Number(Number(x - 1.0))),
|
||||
Some(Value::BigInt(x)) => Some(Value::BigInt(x - BigInt::from(1))),
|
||||
Some(_) => None,
|
||||
None => return,
|
||||
};
|
||||
|
||||
self.set_register(reg, new_value);
|
||||
}
|
||||
|
||||
Instruction::OpNot(a1, dst) => self.apply_unary_op(a1, dst, operations::op_not),
|
||||
Instruction::OpBitNot(a1, dst) => self.apply_unary_op(a1, dst, operations::op_bit_not),
|
||||
Instruction::TypeOf(a1, dst) => self.apply_unary_op(a1, dst, operations::op_typeof),
|
||||
Instruction::UnaryPlus(a1, dst) => self.apply_unary_op(a1, dst, operations::op_unary_plus),
|
||||
Instruction::UnaryMinus(a1, dst) => {
|
||||
self.apply_unary_op(a1, dst, operations::op_unary_minus)
|
||||
}
|
||||
Instruction::Import(_a1, dst)
|
||||
| Instruction::ImportStar(_a1, dst)
|
||||
| Instruction::Cat(_a1, dst) => {
|
||||
// TODO: cat
|
||||
self.set_register(dst, None);
|
||||
}
|
||||
|
||||
Instruction::Yield(_a1, dst) | Instruction::YieldStar(_a1, dst) => {
|
||||
self.set_register(dst, None)
|
||||
}
|
||||
|
||||
Instruction::Throw(_a1) => {}
|
||||
|
||||
Instruction::OpPlus(a1, a2, dst) => self.apply_binary_op(a1, a2, dst, operations::op_plus),
|
||||
Instruction::OpMinus(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_minus)
|
||||
}
|
||||
Instruction::OpMul(a1, a2, dst) => self.apply_binary_op(a1, a2, dst, operations::op_mul),
|
||||
Instruction::OpDiv(a1, a2, dst) => self.apply_binary_op(a1, a2, dst, operations::op_div),
|
||||
Instruction::OpMod(a1, a2, dst) => self.apply_binary_op(a1, a2, dst, operations::op_mod),
|
||||
Instruction::OpExp(a1, a2, dst) => self.apply_binary_op(a1, a2, dst, operations::op_exp),
|
||||
Instruction::OpEq(a1, a2, dst) => self.apply_binary_op(a1, a2, dst, operations::op_eq),
|
||||
Instruction::OpNe(a1, a2, dst) => self.apply_binary_op(a1, a2, dst, operations::op_ne),
|
||||
Instruction::OpTripleEq(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_triple_eq)
|
||||
}
|
||||
Instruction::OpTripleNe(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_triple_ne)
|
||||
}
|
||||
Instruction::OpAnd(a1, a2, dst) => self.apply_binary_op(a1, a2, dst, operations::op_and),
|
||||
Instruction::OpOr(a1, a2, dst) => self.apply_binary_op(a1, a2, dst, operations::op_or),
|
||||
Instruction::OpLess(a1, a2, dst) => self.apply_binary_op(a1, a2, dst, operations::op_less),
|
||||
Instruction::OpLessEq(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_less_eq)
|
||||
}
|
||||
Instruction::OpGreater(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_greater)
|
||||
}
|
||||
Instruction::OpGreaterEq(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_greater_eq)
|
||||
}
|
||||
Instruction::OpNullishCoalesce(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_nullish_coalesce)
|
||||
}
|
||||
Instruction::OpOptionalChain(_a1, _a2, dst) => {
|
||||
// self.apply_binary_op(a1, a2, dst, operations::op_optional_chain)
|
||||
// TODO: op_optional_chain takes mut lhs to optimize, but breaks this pattern
|
||||
self.set_register(dst, None);
|
||||
}
|
||||
Instruction::OpBitAnd(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_bit_and)
|
||||
}
|
||||
Instruction::OpBitOr(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_bit_or)
|
||||
}
|
||||
Instruction::OpBitXor(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_bit_xor)
|
||||
}
|
||||
Instruction::OpLeftShift(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_left_shift)
|
||||
}
|
||||
Instruction::OpRightShift(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_right_shift)
|
||||
}
|
||||
Instruction::OpRightShiftUnsigned(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_right_shift_unsigned)
|
||||
}
|
||||
Instruction::InstanceOf(a1, a2, dst) => {
|
||||
self.apply_binary_op(a1, a2, dst, operations::op_instance_of)
|
||||
}
|
||||
Instruction::In(a1, a2, dst) => self.apply_binary_op(a1, a2, dst, operations::op_in),
|
||||
|
||||
Instruction::Call(_a1, _a2, dst)
|
||||
| Instruction::Bind(_a1, _a2, dst)
|
||||
| Instruction::Sub(_a1, _a2, dst)
|
||||
| Instruction::SubMov(_a1, _a2, dst)
|
||||
| Instruction::New(_a1, _a2, dst) => {
|
||||
self.set_register(dst, None);
|
||||
}
|
||||
|
||||
Instruction::Apply(_a1, _this, _a3, dst) => self.set_register(dst, None),
|
||||
|
||||
Instruction::SubCall(_this, _a2, _a3, dst)
|
||||
| Instruction::ThisSubCall(_this, _a2, _a3, dst) => self.set_register(dst, None),
|
||||
|
||||
Instruction::ConstSubCall(_a1, _a2, _a3, dst) => self.set_register(dst, None),
|
||||
|
||||
Instruction::JmpIf(_a1, _) => {}
|
||||
|
||||
Instruction::Jmp(_) => {}
|
||||
Instruction::SetCatch(_, _) => {}
|
||||
Instruction::UnsetCatch => {}
|
||||
Instruction::RequireMutableThis => {
|
||||
self.mutable_this_established = true;
|
||||
}
|
||||
Instruction::Next(iter, dst) => {
|
||||
self.set_register(iter, None);
|
||||
self.set_register(dst, None);
|
||||
}
|
||||
Instruction::UnpackIterRes(iter_res, value_reg, done) => {
|
||||
self.set_register(iter_res, None);
|
||||
self.set_register(value_reg, None);
|
||||
self.set_register(done, None);
|
||||
}
|
||||
},
|
||||
FnLine::Label(..) => self.clear(),
|
||||
FnLine::Empty | FnLine::Comment(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_register(&mut self, reg: &Register, value: Option<Value>) {
|
||||
let mut registers_to_clear = HashSet::<Register>::new();
|
||||
|
||||
for (k, v) in &mut self.registers {
|
||||
v.visit_values_mut(&mut |value| {
|
||||
if let Value::Register(reg_value) = value {
|
||||
if reg_value.name == reg.name {
|
||||
registers_to_clear.insert(k.clone());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for reg_to_clear in registers_to_clear {
|
||||
self.registers.remove(®_to_clear);
|
||||
}
|
||||
|
||||
match value {
|
||||
Some(value) => self.registers.insert(reg.clone(), value),
|
||||
None => self.registers.remove(reg),
|
||||
};
|
||||
}
|
||||
|
||||
fn apply_unary_op(&mut self, arg: &Value, dst: &Register, op: fn(input: &Val) -> Val) {
|
||||
match self.apply_unary_op_impl(arg, dst, op) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
self.set_register(dst, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_unary_op_impl(
|
||||
&mut self,
|
||||
arg: &Value,
|
||||
dst: &Register,
|
||||
op: fn(input: &Val) -> Val,
|
||||
) -> Result<(), Val> {
|
||||
let arg = arg.clone().try_to_val()?;
|
||||
let value = op(&arg).try_to_value()?;
|
||||
|
||||
self.set_register(dst, Some(value));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply_binary_op(
|
||||
&mut self,
|
||||
left: &Value,
|
||||
right: &Value,
|
||||
dst: &Register,
|
||||
op: fn(left: &Val, right: &Val) -> Result<Val, Val>,
|
||||
) {
|
||||
match self.apply_binary_op_impl(left, right, dst, op) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
self.set_register(dst, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_binary_op_impl(
|
||||
&mut self,
|
||||
left: &Value,
|
||||
right: &Value,
|
||||
dst: &Register,
|
||||
op: fn(left: &Val, right: &Val) -> Result<Val, Val>,
|
||||
) -> Result<(), Val> {
|
||||
let left = left.clone().try_to_val()?;
|
||||
let right = right.clone().try_to_val()?;
|
||||
let value = op(&left, &right)?.try_to_value()?;
|
||||
|
||||
self.set_register(dst, Some(value));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn simplify_fn(mut state: FnState, fn_: &mut Function) {
|
||||
|
||||
52
valuescript_compiler/src/optimization/try_to_val.rs
Normal file
52
valuescript_compiler/src/optimization/try_to_val.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use valuescript_vm::{
|
||||
vs_object::VsObject,
|
||||
vs_value::{ToVal, Val},
|
||||
};
|
||||
|
||||
use crate::asm::{Number, Value};
|
||||
|
||||
pub trait TryToVal {
|
||||
fn try_to_val(self) -> Result<Val, Val>;
|
||||
}
|
||||
|
||||
impl TryToVal for Value {
|
||||
fn try_to_val(self) -> Result<Val, Val> {
|
||||
Ok(match self {
|
||||
Value::Undefined => Val::Undefined,
|
||||
Value::Null => Val::Null,
|
||||
Value::Bool(b) => b.to_val(),
|
||||
Value::Number(Number(n)) => n.to_val(),
|
||||
Value::BigInt(n) => n.to_val(),
|
||||
Value::String(s) => s.to_val(),
|
||||
Value::Array(arr) => {
|
||||
let mut result = Vec::<Val>::new();
|
||||
|
||||
for value in arr.values {
|
||||
result.push(value.try_to_val()?);
|
||||
}
|
||||
|
||||
result.to_val()
|
||||
}
|
||||
Value::Object(obj) => {
|
||||
let mut string_map = BTreeMap::<String, Val>::new();
|
||||
|
||||
for (key, value) in obj.properties {
|
||||
string_map.insert(key.try_to_val()?.to_string(), value.try_to_val()?);
|
||||
}
|
||||
|
||||
VsObject {
|
||||
string_map,
|
||||
symbol_map: Default::default(),
|
||||
prototype: None,
|
||||
}
|
||||
.to_val()
|
||||
}
|
||||
|
||||
Value::Void | Value::Register(..) | Value::Pointer(..) | Value::Builtin(..) => {
|
||||
return Err("Invalid argument".to_val());
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
66
valuescript_compiler/src/optimization/try_to_value.rs
Normal file
66
valuescript_compiler/src/optimization/try_to_value.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use valuescript_vm::{
|
||||
vs_value::{ToVal, Val},
|
||||
VsSymbol,
|
||||
};
|
||||
|
||||
use crate::asm::{Array, Builtin, Number, Object, Value};
|
||||
|
||||
pub trait TryToValue {
|
||||
fn try_to_value(&self) -> Result<Value, Val>;
|
||||
}
|
||||
|
||||
impl TryToValue for Val {
|
||||
fn try_to_value(&self) -> Result<Value, Val> {
|
||||
Ok(match self {
|
||||
Val::Void => Value::Undefined,
|
||||
Val::Undefined => Value::Undefined,
|
||||
Val::Null => Value::Null,
|
||||
Val::Bool(b) => Value::Bool(*b),
|
||||
Val::Number(n) => Value::Number(Number(*n)),
|
||||
Val::BigInt(n) => Value::BigInt(n.clone()),
|
||||
Val::Symbol(sym) => match sym {
|
||||
VsSymbol::ITERATOR => Value::Builtin(Builtin {
|
||||
name: "SymbolIterator".to_string(),
|
||||
}),
|
||||
},
|
||||
Val::String(s) => Value::String(s.to_string()),
|
||||
Val::Array(arr) => {
|
||||
let mut values = Vec::<Value>::new();
|
||||
|
||||
for value in &arr.elements {
|
||||
values.push(value.try_to_value()?);
|
||||
}
|
||||
|
||||
Value::Array(Box::new(Array { values }))
|
||||
}
|
||||
Val::Object(obj) => {
|
||||
if obj.prototype.is_some() {
|
||||
return Err("can't (yet?) convert object with prototype to Value".to_val());
|
||||
}
|
||||
|
||||
let mut properties = Vec::<(Value, Value)>::new();
|
||||
|
||||
for (k, v) in &obj.symbol_map {
|
||||
let k = match k {
|
||||
VsSymbol::ITERATOR => Value::Builtin(Builtin {
|
||||
name: "SymbolIterator".to_string(),
|
||||
}),
|
||||
};
|
||||
|
||||
properties.push((k, v.try_to_value()?));
|
||||
}
|
||||
|
||||
for (k, v) in &obj.string_map {
|
||||
properties.push((Value::String(k.clone()), v.try_to_value()?));
|
||||
}
|
||||
|
||||
Value::Object(Box::new(Object { properties }))
|
||||
}
|
||||
Val::Function(..)
|
||||
| Val::Class(..)
|
||||
| Val::Static(..)
|
||||
| Val::Dynamic(..)
|
||||
| Val::CopyCounter(..) => return Err("TODO: support more of these".to_val()),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -29,4 +29,5 @@ pub mod vs_value;
|
||||
|
||||
pub use bytecode::Bytecode;
|
||||
pub use virtual_machine::VirtualMachine;
|
||||
pub use vs_symbol::VsSymbol;
|
||||
pub use vs_value::{LoadFunctionResult, ValTrait};
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
rc::Rc,
|
||||
};
|
||||
use std::{collections::HashMap, rc::Rc};
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use valuescript_compiler::{
|
||||
asm::{Number, Value},
|
||||
assemble,
|
||||
assembly_parser::AssemblyParser,
|
||||
compile as compile_internal, CompileResult, Diagnostic, ResolvedPath,
|
||||
asm::Value, assemble, assembly_parser::AssemblyParser, compile as compile_internal,
|
||||
CompileResult, Diagnostic, ResolvedPath, TryToVal,
|
||||
};
|
||||
use valuescript_vm::{
|
||||
vs_object::VsObject,
|
||||
vs_value::{ToVal, Val},
|
||||
Bytecode, LoadFunctionResult, ValTrait, VirtualMachine,
|
||||
};
|
||||
@@ -175,47 +169,3 @@ fn parse_args(args: &str) -> Result<Vec<Val>, Val> {
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub trait TryToVal {
|
||||
fn try_to_val(self) -> Result<Val, Val>;
|
||||
}
|
||||
|
||||
impl TryToVal for Value {
|
||||
fn try_to_val(self) -> Result<Val, Val> {
|
||||
Ok(match self {
|
||||
Value::Undefined => Val::Undefined,
|
||||
Value::Null => Val::Null,
|
||||
Value::Bool(b) => b.to_val(),
|
||||
Value::Number(Number(n)) => n.to_val(),
|
||||
Value::BigInt(n) => n.to_val(),
|
||||
Value::String(s) => s.to_val(),
|
||||
Value::Array(arr) => {
|
||||
let mut result = Vec::<Val>::new();
|
||||
|
||||
for value in arr.values {
|
||||
result.push(value.try_to_val()?);
|
||||
}
|
||||
|
||||
result.to_val()
|
||||
}
|
||||
Value::Object(obj) => {
|
||||
let mut string_map = BTreeMap::<String, Val>::new();
|
||||
|
||||
for (key, value) in obj.properties {
|
||||
string_map.insert(key.try_to_val()?.to_string(), value.try_to_val()?);
|
||||
}
|
||||
|
||||
VsObject {
|
||||
string_map,
|
||||
symbol_map: Default::default(),
|
||||
prototype: None,
|
||||
}
|
||||
.to_val()
|
||||
}
|
||||
|
||||
Value::Void | Value::Register(..) | Value::Pointer(..) | Value::Builtin(..) => {
|
||||
return Err("Invalid argument".to_val());
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user