mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-04-18 03:00:27 -04:00
Implement jsx instruction
This commit is contained in:
@@ -7,6 +7,7 @@ use crate::builtins::type_error_builtin::ToTypeError;
|
||||
use crate::bytecode_decoder::BytecodeDecoder;
|
||||
use crate::bytecode_decoder::BytecodeType;
|
||||
use crate::cat_stack_frame::CatStackFrame;
|
||||
use crate::jsx_element::JsxElement;
|
||||
use crate::native_function::ThisWrapper;
|
||||
use crate::operations;
|
||||
use crate::operations::op_delete;
|
||||
@@ -14,6 +15,7 @@ use crate::stack_frame::FrameStepOk;
|
||||
use crate::stack_frame::FrameStepResult;
|
||||
use crate::stack_frame::{CallResult, StackFrame, StackFrameTrait};
|
||||
use crate::vs_object::VsObject;
|
||||
use crate::vs_value::ToDynamicVal;
|
||||
use crate::vs_value::ToVal;
|
||||
use crate::vs_value::{LoadFunctionResult, Val, ValTrait};
|
||||
|
||||
@@ -626,7 +628,60 @@ impl StackFrameTrait for BytecodeStackFrame {
|
||||
return Ok(FrameStepOk::Continue);
|
||||
}
|
||||
|
||||
Jsx => todo!(),
|
||||
Jsx => {
|
||||
let tag = self.decoder.decode_val(&mut self.registers);
|
||||
let attrs_val = self.decoder.decode_val(&mut self.registers);
|
||||
let children_val = self.decoder.decode_val(&mut self.registers);
|
||||
|
||||
let mut attrs = Vec::<(String, Val)>::new();
|
||||
|
||||
match attrs_val {
|
||||
Val::Array(array) => {
|
||||
for attr in &array.elements {
|
||||
match attr {
|
||||
Val::Array(array) => {
|
||||
if array.elements.len() != 2 {
|
||||
return Err("Unexpected non-pair attribute".to_type_error());
|
||||
}
|
||||
|
||||
let name = match &array.elements[0] {
|
||||
Val::String(str) => str.to_string(),
|
||||
_ => return Err("Unexpected non-string attribute name".to_type_error()),
|
||||
};
|
||||
|
||||
let value = array.elements[1].clone();
|
||||
|
||||
attrs.push((name, value));
|
||||
}
|
||||
_ => return Err("Unexpected non-array attrs".to_type_error()),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return Err("Unexpected non-array attrs".to_type_error()),
|
||||
}
|
||||
|
||||
let children = match children_val {
|
||||
Val::Array(array) => array.elements.clone(),
|
||||
_ => return Err("Unexpected non-array children".to_type_error()),
|
||||
};
|
||||
|
||||
let res = JsxElement {
|
||||
tag: match tag {
|
||||
Val::Void => None,
|
||||
Val::String(str) => Some(str.to_string()),
|
||||
_ => return Err("Unexpected non-string tag".to_type_error()),
|
||||
},
|
||||
attrs,
|
||||
children,
|
||||
}
|
||||
.to_dynamic_val();
|
||||
|
||||
if let Some(i) = self.decoder.decode_register_index() {
|
||||
self.registers[i] = res;
|
||||
}
|
||||
|
||||
return Ok(FrameStepOk::Continue);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(FrameStepOk::Continue)
|
||||
|
||||
160
valuescript_vm/src/jsx_element.rs
Normal file
160
valuescript_vm/src/jsx_element.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
use std::{fmt, rc::Rc};
|
||||
|
||||
use num_bigint::BigInt;
|
||||
|
||||
use crate::{
|
||||
builtins::type_error_builtin::ToTypeError,
|
||||
vs_array::VsArray,
|
||||
vs_class::VsClass,
|
||||
vs_value::{Val, VsType},
|
||||
LoadFunctionResult, ValTrait,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct JsxElement {
|
||||
pub tag: Option<String>,
|
||||
pub attrs: Vec<(String, Val)>,
|
||||
pub children: Vec<Val>,
|
||||
}
|
||||
|
||||
impl ValTrait for JsxElement {
|
||||
fn typeof_(&self) -> VsType {
|
||||
VsType::Object
|
||||
}
|
||||
|
||||
fn to_number(&self) -> f64 {
|
||||
f64::NAN
|
||||
}
|
||||
|
||||
fn to_index(&self) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
|
||||
fn is_primitive(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn is_truthy(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn is_nullish(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn bind(&self, _params: Vec<Val>) -> Option<Val> {
|
||||
None
|
||||
}
|
||||
|
||||
fn as_bigint_data(&self) -> Option<BigInt> {
|
||||
None
|
||||
}
|
||||
|
||||
fn as_array_data(&self) -> Option<Rc<VsArray>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn as_class_data(&self) -> Option<Rc<VsClass>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn load_function(&self) -> LoadFunctionResult {
|
||||
LoadFunctionResult::NotAFunction
|
||||
}
|
||||
|
||||
fn sub(&self, _key: &Val) -> Result<Val, Val> {
|
||||
Ok(Val::Undefined)
|
||||
}
|
||||
|
||||
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 jsx element".to_type_error())
|
||||
}
|
||||
|
||||
fn pretty_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.tag.is_none() && self.children.is_empty() {
|
||||
return write!(f, "\x1b[36m<></>\x1b[39m");
|
||||
}
|
||||
|
||||
let tag_str = match &self.tag {
|
||||
Some(str) => str.clone(),
|
||||
None => "".to_owned(),
|
||||
};
|
||||
|
||||
if self.children.is_empty() {
|
||||
write!(f, "\x1b[36m<{}\x1b[39m", tag_str)?;
|
||||
write_attributes_pretty(f, &self.attrs)?;
|
||||
write!(f, " \x1b[36m/>\x1b[39m")
|
||||
} else {
|
||||
write!(f, "\x1b[36m<{}\x1b[39m", tag_str)?;
|
||||
write_attributes_pretty(f, &self.attrs)?;
|
||||
write!(f, "\x1b[36m>\x1b[39m")?;
|
||||
|
||||
for child in &self.children {
|
||||
if let Some(jsx_child) = try_to_jsx_element(child) {
|
||||
jsx_child.pretty_fmt(f)?;
|
||||
} else {
|
||||
write!(f, "{}", child)?;
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, "\x1b[36m</{}>\x1b[39m", tag_str)
|
||||
}
|
||||
}
|
||||
|
||||
fn codify(&self) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for JsxElement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let tag_str = match &self.tag {
|
||||
Some(str) => str.clone(),
|
||||
None => "".to_owned(),
|
||||
};
|
||||
|
||||
if self.children.is_empty() {
|
||||
write!(f, "<{}", tag_str)?;
|
||||
write_attributes(f, &self.attrs)?;
|
||||
write!(f, " />")
|
||||
} else {
|
||||
write!(f, "<{}", tag_str)?;
|
||||
write_attributes(f, &self.attrs)?;
|
||||
write!(f, ">")?;
|
||||
|
||||
for child in &self.children {
|
||||
write!(f, "{}", child)?;
|
||||
}
|
||||
|
||||
write!(f, "</{}>", tag_str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_attributes(f: &mut fmt::Formatter<'_>, attrs: &Vec<(String, Val)>) -> fmt::Result {
|
||||
for (key, val) in attrs {
|
||||
write!(f, " {}=\x1b[33m{}\x1b[39m", key, val)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_attributes_pretty(f: &mut fmt::Formatter<'_>, attrs: &Vec<(String, Val)>) -> fmt::Result {
|
||||
for (key, val) in attrs {
|
||||
write!(f, " {}=\x1b[33m{}\x1b[39m", key, val)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn try_to_jsx_element(val: &Val) -> Option<Rc<JsxElement>> {
|
||||
match val {
|
||||
Val::Dynamic(dynamic) => dynamic.as_any().downcast_ref().cloned(),
|
||||
Val::StoragePtr(ptr) => try_to_jsx_element(&ptr.get()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ mod first_stack_frame;
|
||||
mod generator;
|
||||
mod helpers;
|
||||
mod iteration;
|
||||
mod jsx_element;
|
||||
mod make_generator_frame;
|
||||
mod native_frame_function;
|
||||
mod native_function;
|
||||
|
||||
@@ -54,10 +54,7 @@ pub fn format_from_path(file_path: &str) -> RunFormat {
|
||||
.unwrap_or("");
|
||||
|
||||
match ext {
|
||||
"ts" => RunFormat::TypeScript,
|
||||
"mts" => RunFormat::TypeScript,
|
||||
"js" => RunFormat::TypeScript,
|
||||
"mjs" => RunFormat::TypeScript,
|
||||
"ts" | "tsx" | "mts" | "js" | "jsx" | "mjs" => RunFormat::TypeScript,
|
||||
"vsm" => RunFormat::Assembly,
|
||||
"vsb" => RunFormat::Bytecode,
|
||||
_ => std::panic!("Unrecognized file extension \"{}\"", ext),
|
||||
|
||||
Reference in New Issue
Block a user