Phase 1.2-1.6: replace variables HashMap<String,String> with HashMap<String,Value>, rewrite str_to_dyn/dyn_to_str -> value_to_dynamic/dynamic_to_value, update resolve_string/evaluate_condition/is_truthy for Value

This commit is contained in:
Glint Dev
2026-07-21 20:32:29 +03:00
parent 5597f07787
commit 30cf2e5e26
7 changed files with 542 additions and 53 deletions

View File

@@ -10,10 +10,12 @@ pub use rhei::RheiContext;
use style::StyleSheet as SS;
pub use types::{ComponentDef, Document, Element, InterpError};
use compact_str::CompactString;
use opcodes::*;
use reader::Reader;
use rhei::{dyn_to_str, str_to_dyn, RHEI_PREFIX};
use rhei::{value_to_dynamic, dynamic_to_value, RHEI_PREFIX};
use style::{AncestorInfo, ComputedStyle, StructuralContext};
pub use types::Value;
use regex::Regex;
use std::collections::HashMap;
use std::sync::OnceLock;
@@ -51,7 +53,7 @@ impl Interpreter {
fn parse_block_elements<'a>(
r: &mut Reader<'a>,
variables: &mut HashMap<String, String>,
variables: &mut HashMap<String, Value>,
components: &mut HashMap<String, ComponentDef<'a>>,
rhei_scripts: &mut Vec<String>,
stylesheet: &mut SS,
@@ -75,7 +77,7 @@ impl Interpreter {
OP_GLOBAL | OP_LET => {
let name = r.read_string()?;
let vop = r.read_byte()?;
if let Some(value) = r.read_value_as_string(vop)? {
if let Some(value) = r.read_value(vop)? {
variables.insert(name, value);
}
}
@@ -292,7 +294,7 @@ impl Interpreter {
pub fn evaluate_vdom<'a>(
templates: &[Element<'a>],
variables: &mut HashMap<String, String>,
variables: &mut HashMap<String, Value>,
components: &HashMap<String, ComponentDef<'a>>,
rhei: &RheiContext,
stylesheet: &SS,
@@ -357,7 +359,7 @@ impl Interpreter {
let source_expr = el.get_prop("source").unwrap_or_default();
let resolved_source = if let Some(expr) = source_expr.strip_prefix(RHEI_PREFIX) {
Self::normalize_rhai_array(&rhei.eval_expr(expr, variables))
Self::normalize_rhai_array(&rhei.eval_expr(expr, variables).to_owned_string())
} else {
Self::resolve_string(source_expr, variables).into_owned()
};
@@ -369,7 +371,7 @@ impl Interpreter {
};
for item in items {
let old_val = variables.insert(var_name.to_string(), item);
let old_val = variables.insert(var_name.to_string(), Value::Str(CompactString::new(item)));
output.extend(Self::evaluate_vdom(
&el.children, variables, components, rhei, stylesheet, ancestors,
@@ -397,7 +399,7 @@ impl Interpreter {
let mut old_vals = Vec::with_capacity(new_args.len());
for (k, v) in new_args {
old_vals.push((k.clone(), variables.insert(k, v)));
old_vals.push((k.clone(), variables.insert(k, Value::from(v))));
}
let mut vcomp = Element::new(el.type_name);
@@ -489,9 +491,9 @@ impl Interpreter {
stylesheet.matching_rules(el.type_name, el_id, &classes, active_pseudo, structural, ancestors, preceding_siblings, &el_attributes)
}
fn resolve_prop(v: &str, variables: &HashMap<String, String>, rhei: &RheiContext) -> String {
fn resolve_prop(v: &str, variables: &HashMap<String, Value>, rhei: &RheiContext) -> String {
if let Some(expr) = v.strip_prefix(RHEI_PREFIX) {
rhei.eval_expr(expr, variables)
rhei.eval_expr(expr, variables).to_owned_string().into()
} else {
Self::resolve_string(v, variables).into_owned()
}
@@ -499,7 +501,7 @@ impl Interpreter {
fn evaluate_condition(
cond: &str,
variables: &HashMap<String, String>,
variables: &HashMap<String, Value>,
rhei: &RheiContext,
) -> bool {
if let Some(expr) = cond.strip_prefix(RHEI_PREFIX) {
@@ -515,7 +517,7 @@ impl Interpreter {
let resolved = Self::resolve_string(&clean, variables).trim().to_string();
if Self::is_truthy(&resolved) { return true; }
if Self::is_truthy_str(&resolved) { return true; }
if resolved == "false" || resolved == "0" || resolved.is_empty() { return false; }
let operators: [(&str, fn(f64, f64) -> bool); 6] = [
@@ -542,7 +544,19 @@ impl Interpreter {
}
#[inline]
fn is_truthy(s: &str) -> bool {
fn is_truthy(v: &Value) -> bool {
match v {
Value::Bool(b) => *b,
Value::Int(i) => *i != 0,
Value::Float(f) => *f != 0.0,
Value::Str(s) => Self::is_truthy_str(s),
Value::None => false,
Value::Array(a) => !a.is_empty(),
}
}
#[inline]
fn is_truthy_str(s: &str) -> bool {
match s.trim() {
"" | "false" | "0" | "null" => false,
"true" | "1" => true,
@@ -563,7 +577,7 @@ impl Interpreter {
}
}
pub fn resolve_string<'a>(val: &'a str, scope: &HashMap<String, String>) -> Cow<'a, str> {
pub fn resolve_string<'a>(val: &'a str, scope: &HashMap<String, Value>) -> Cow<'a, str> {
if !val.contains('$') {
return Cow::Borrowed(val);
}
@@ -582,7 +596,8 @@ impl Interpreter {
}
}
if let Some(resolved) = scope.get(&var_name) {
result.push_str(resolved);
let formatted = resolved.to_owned_string();
result.push_str(&formatted);
} else {
result.push('$');
result.push_str(&var_name);