ConcatStrings

This commit is contained in:
2026-05-02 23:39:40 +08:00
parent 1550868e90
commit 9d10fa7da3
6 changed files with 68 additions and 20 deletions
+2 -1
View File
@@ -291,7 +291,7 @@ impl<'a, Ctx: DisassemblerContext> Disassembler<'a, Ctx> {
Op::Call => { Op::Call => {
self.read_operand_data(); self.read_operand_data();
("Call", "arg=?".into()) ("Call", "arg=?".into())
}, }
Op::DispatchPrimOp => { Op::DispatchPrimOp => {
let id = BuiltinId::try_from_primitive(self.read_u8()).expect("invalid builtin id"); let id = BuiltinId::try_from_primitive(self.read_u8()).expect("invalid builtin id");
("DispatchPrimOp", format!("id={id:?}")) ("DispatchPrimOp", format!("id={id:?}"))
@@ -419,6 +419,7 @@ impl<'a, Ctx: DisassemblerContext> Disassembler<'a, Ctx> {
let force = self.read_u8(); let force = self.read_u8();
("ConcatStrings", format!("count={} force={}", count, force)) ("ConcatStrings", format!("count={} force={}", count, force))
} }
Op::CoerceToString => ("CoerceToString", String::new()),
Op::ResolvePath => ("ResolvePath", String::new()), Op::ResolvePath => ("ResolvePath", String::new()),
Op::Assert => { Op::Assert => {
let raw_idx = self.read_u32(); let raw_idx = self.read_u32();
+17 -11
View File
@@ -77,6 +77,8 @@ pub enum Op {
JumpIfTrue, JumpIfTrue,
Jump, Jump,
CoerceToString,
ConcatStrings, ConcatStrings,
ResolvePath, ResolvePath,
@@ -250,6 +252,11 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
self.ctx.get_code_mut().push(op as u8); self.ctx.get_code_mut().push(op as u8);
} }
#[inline]
fn emit_bool(&mut self, val: bool) {
self.emit_u8(u8::from(val));
}
#[inline] #[inline]
fn emit_u8(&mut self, val: u8) { fn emit_u8(&mut self, val: u8) {
self.ctx.get_code_mut().push(val); self.ctx.get_code_mut().push(val);
@@ -615,17 +622,16 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
); );
} }
&Ir::ConcatStrings { &Ir::ConcatStrings {
parts: _, ref parts,
force_string: _, force_string,
} => { } => {
todo!("redesign ConcatStrings"); for &part in parts.iter() {
// self.emit_op(Op::ConcatStrings); self.emit_expr(part);
// self.emit_u16(parts.len() as u16); self.emit_op(Op::CoerceToString);
// self.emit_u8(if force_string { 1 } else { 0 }); }
// for &part in parts.iter() { self.emit_op(Op::ConcatStrings);
// let operand = self.inline_maybe_thunk(part); self.emit_u16(parts.len() as u16);
// self.emit_inline_operand(operand); self.emit_bool(force_string);
// }
} }
&Ir::HasAttr { lhs, ref rhs } => { &Ir::HasAttr { lhs, ref rhs } => {
self.emit_has_attr(lhs, rhs); self.emit_has_attr(lhs, rhs);
@@ -842,7 +848,7 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
self.emit_u32(total_slots as u32); self.emit_u32(total_slots as u32);
self.emit_u16(required.len() as u16); self.emit_u16(required.len() as u16);
self.emit_u16(optional.len() as u16); self.emit_u16(optional.len() as u16);
self.emit_u8(if *ellipsis { 1 } else { 0 }); self.emit_bool(*ellipsis);
for &(sym, _) in required.iter() { for &(sym, _) in required.iter() {
self.emit_str_id(sym); self.emit_str_id(sym);
+4
View File
@@ -180,6 +180,8 @@ tail_fn!(op_jump_if_false, (reader, mc));
tail_fn!(op_jump_if_true, (reader, mc)); tail_fn!(op_jump_if_true, (reader, mc));
tail_fn!(op_jump, (reader)); tail_fn!(op_jump, (reader));
tail_fn!(op_coerce_to_string, (reader, mc));
tail_fn!(op_concat_strings, (ctx, reader, mc)); tail_fn!(op_concat_strings, (ctx, reader, mc));
tail_fn!(op_resolve_path, (ctx)); tail_fn!(op_resolve_path, (ctx));
@@ -272,6 +274,8 @@ table! {
JumpIfTrue => op_jump_if_true, JumpIfTrue => op_jump_if_true,
Jump => op_jump, Jump => op_jump,
CoerceToString => op_coerce_to_string,
ConcatStrings => op_concat_strings, ConcatStrings => op_concat_strings,
ResolvePath => op_resolve_path, ResolvePath => op_resolve_path,
+4 -1
View File
@@ -326,6 +326,9 @@ fn numeric_binop<'gc>(
(Some(NixNum::Float(a)), Some(NixNum::Int(b))) => { (Some(NixNum::Float(a)), Some(NixNum::Int(b))) => {
Ok(Value::new_float(float_op(a, b as f64))) Ok(Value::new_float(float_op(a, b as f64)))
} }
_ => Err(crate::vm_err("cannot perform arithmetic on non-numbers")), _ => Err(crate::vm_err(format!(
"cannot perform arithmetic on non-numbers: {:?}",
(lhs.ty(), rhs.ty())
))),
} }
} }
+39 -6
View File
@@ -1,6 +1,8 @@
use fix_builtins::BuiltinId; use fix_builtins::BuiltinId;
use fix_common::StringId;
use num_enum::TryFromPrimitive; use num_enum::TryFromPrimitive;
use crate::value::{NixString, StrictValue};
use crate::{BytecodeReader, PrimOp, Step, Value, VmRuntimeCtx}; use crate::{BytecodeReader, PrimOp, Step, Value, VmRuntimeCtx};
impl<'gc> crate::Vm<'gc> { impl<'gc> crate::Vm<'gc> {
@@ -34,6 +36,21 @@ impl<'gc> crate::Vm<'gc> {
todo!("LoadScopedBinding"); todo!("LoadScopedBinding");
} }
#[inline(always)]
pub(crate) fn op_coerce_to_string(
&mut self,
reader: &mut BytecodeReader<'_>,
mc: &gc_arena::Mutation<'gc>,
) -> Step {
let val = self.try_force::<StrictValue>(reader, mc)?;
if val.is::<StringId>() || val.is::<NixString>() {
self.push(val.relax());
} else {
todo!("coerce other types to string: {:?}", val.ty());
}
Step::Continue(())
}
#[inline(always)] #[inline(always)]
pub(crate) fn op_concat_strings( pub(crate) fn op_concat_strings(
&mut self, &mut self,
@@ -41,14 +58,30 @@ impl<'gc> crate::Vm<'gc> {
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
_mc: &gc_arena::Mutation<'gc>, _mc: &gc_arena::Mutation<'gc>,
) -> Step { ) -> Step {
let _parts_count = reader.read_u16() as usize; use crate::VmRuntimeCtxExt;
let count = reader.read_u16() as usize;
let _force_string = reader.read_u8() != 0; let _force_string = reader.read_u8() != 0;
let mut _operands: smallvec::SmallVec<[crate::OperandData; 4]> =
smallvec::SmallVec::with_capacity(_parts_count); let mut total_len = 0;
for _ in 0.._parts_count { for i in 0..count {
_operands.push(reader.read_operand_data(ctx)); let val = self.peek_forced(count - 1 - i);
let s = ctx.get_string(val).expect("coerced");
total_len += s.len();
} }
todo!("implement ConcatStrings (force parts, coerce to string, concatenate)");
let mut result = String::with_capacity(total_len);
for i in 0..count {
let val = self.peek_forced(count - 1 - i);
let s = ctx.get_string(val).expect("coerced");
result.push_str(s);
}
self.stack.truncate(self.stack.len() - count);
let sid = ctx.intern_string(result);
self.push(Value::new_inline(sid));
Step::Continue(())
} }
#[inline(always)] #[inline(always)]
+2 -1
View File
@@ -492,7 +492,7 @@ impl<'gc> Vm<'gc> {
}); });
self.push(func); self.push(func);
self.call(reader, mc, arg, resume_pc) self.call(reader, mc, arg, resume_pc)
}, }
ThunkState::Blackhole => { ThunkState::Blackhole => {
self.finish_err(Error::eval_error("infinite recursion encountered")) self.finish_err(Error::eval_error("infinite recursion encountered"))
} }
@@ -666,6 +666,7 @@ impl<'gc> Vm<'gc> {
Jump => self.op_jump(&mut reader), Jump => self.op_jump(&mut reader),
ConcatStrings => self.op_concat_strings(ctx, &mut reader, mc), ConcatStrings => self.op_concat_strings(ctx, &mut reader, mc),
CoerceToString => self.op_coerce_to_string(&mut reader, mc),
ResolvePath => self.op_resolve_path(ctx), ResolvePath => self.op_resolve_path(ctx),
Assert => self.op_assert(&mut reader), Assert => self.op_assert(&mut reader),