ConcatStrings
This commit is contained in:
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|
||||||
|
|||||||
@@ -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())
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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),
|
||||||
|
|||||||
Reference in New Issue
Block a user