From 4f7d94f41b498b6d90aabb7d9ba5ac41ea3e8ce9 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sat, 2 May 2026 21:23:39 +0800 Subject: [PATCH] implement dynamic key; implement __curPos; other small changes --- fix-codegen/src/disassembler.rs | 42 +++++++------- fix-codegen/src/lib.rs | 18 +++--- fix-ir/src/downgrade.rs | 76 ++++++++++++++++++++++++-- fix-ir/src/lib.rs | 1 - fix-vm/src/bytecode_reader.rs | 14 +---- fix-vm/src/dispatch_tailcall.rs | 2 - fix-vm/src/instructions/arithmetic.rs | 4 +- fix-vm/src/instructions/builtins.rs | 10 ++-- fix-vm/src/instructions/collections.rs | 58 ++++++++++++-------- fix-vm/src/instructions/misc.rs | 6 -- fix-vm/src/lib.rs | 25 +++++---- fix-vm/src/value.rs | 50 +++++------------ fix/src/lib.rs | 4 +- 13 files changed, 169 insertions(+), 141 deletions(-) diff --git a/fix-codegen/src/disassembler.rs b/fix-codegen/src/disassembler.rs index bde0b35..45d0b6a 100644 --- a/fix-codegen/src/disassembler.rs +++ b/fix-codegen/src/disassembler.rs @@ -1,9 +1,10 @@ use std::fmt::Write; use colored::Colorize; +use fix_builtins::BuiltinId; use num_enum::TryFromPrimitive; -use crate::{AttrKeyType, InstructionPtr, Op, OperandType}; +use crate::{InstructionPtr, Op, OperandType}; pub trait DisassemblerContext { fn resolve_string(&self, id: u32) -> &str; @@ -292,31 +293,30 @@ impl<'a, Ctx: DisassemblerContext> Disassembler<'a, Ctx> { ("Call", "arg=?".into()) }, Op::DispatchPrimOp => { - todo!(); + let id = BuiltinId::try_from_primitive(self.read_u8()).expect("invalid builtin id"); + ("DispatchPrimOp", format!("id={id:?}")) } Op::MakeAttrs => { - let count = self.read_u32(); - let mut args = format!("size={}", count); - for _ in 0..count { - let key_tag = self.read_u8(); - let key_ty = - AttrKeyType::try_from_primitive(key_tag).expect("invalid attr key type"); - match key_ty { - AttrKeyType::Static => { - let key_id = self.read_u32(); - let _ = - write!(args, " [{}={}", self.ctx.resolve_string(key_id), key_id); - } - AttrKeyType::Dynamic => { - let _ = write!(args, " [dyn"); - self.read_operand_data(); - } - } + let static_count = self.read_u32(); + let dynamic_count = self.read_u32(); + let mut args = format!("static={} dynamic={}", static_count, dynamic_count); + + for _ in 0..static_count { + let key_id = self.read_u32(); + let _ = write!(args, " [{}={}", self.ctx.resolve_string(key_id), key_id); self.read_operand_data(); let _span_id = self.read_u32(); args.push(']'); } + + for _ in 0..dynamic_count { + let _ = write!(args, " [dyn"); + self.read_operand_data(); + let _span_id = self.read_u32(); + args.push(']'); + } + ("MakeAttrs", args) } Op::MakeEmptyAttrs => ("MakeEmptyAttrs", String::new()), @@ -442,10 +442,6 @@ impl<'a, Ctx: DisassemblerContext> Disassembler<'a, Ctx> { let id = self.read_u8(); ("LoadBuiltin", format!("id={}", id)) } - Op::MkPos => { - let span_id = self.read_u32(); - ("MkPos", format!("id={}", span_id)) - } Op::LoadReplBinding => { let idx = self.read_u32(); let name = self.ctx.resolve_string(idx); diff --git a/fix-codegen/src/lib.rs b/fix-codegen/src/lib.rs index b253297..659d138 100644 --- a/fix-codegen/src/lib.rs +++ b/fix-codegen/src/lib.rs @@ -90,8 +90,6 @@ pub enum Op { LoadBuiltins, LoadBuiltin, - MkPos, - LoadReplBinding, LoadScopedBinding, @@ -646,11 +644,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { self.emit_str_id(raw_idx); self.emit_u32(span_id); } - &Ir::CurPos(span) => { - let span_id = self.ctx.register_span(span); - self.emit_op(Op::MkPos); - self.emit_u32(span_id); - } &Ir::ReplBinding(name) => { self.emit_op(Op::LoadReplBinding); self.emit_str_id(name); @@ -879,19 +872,22 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { return; } - let total = stcs.len() + dyns.len(); + for &(key_expr, _val, _span) in dyns.iter() { + self.emit_expr(key_expr); + } + self.emit_op(Op::MakeAttrs); - self.emit_u32(total as u32); + self.emit_u32(stcs.len() as u32); + self.emit_u32(dyns.len() as u32); for (&sym, &(val, span)) in stcs.iter() { - self.emit_u8(AttrKeyType::Static as u8); self.emit_str_id(sym); self.emit_maybe_thunk(val); let span_id = self.ctx.register_span(span); self.emit_u32(span_id); } + for &(_key, val, span) in dyns.iter() { - self.emit_u8(AttrKeyType::Dynamic as u8); self.emit_maybe_thunk(val); let span_id = self.ctx.register_span(span); self.emit_u32(span_id); diff --git a/fix-ir/src/downgrade.rs b/fix-ir/src/downgrade.rs index 336b6b5..44222c4 100644 --- a/fix-ir/src/downgrade.rs +++ b/fix-ir/src/downgrade.rs @@ -98,7 +98,7 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo AttrSet(attrs) => attrs.downgrade(ctx), UnaryOp(op) => op.downgrade(ctx), Ident(ident) => ident.downgrade(ctx), - CurPos(curpos) => Ok(ctx.new_expr(Ir::CurPos(curpos.syntax().text_range()))), + CurPos(curpos) => curpos.downgrade(ctx), With(with) => with.downgrade(ctx), HasAttr(has) => has.downgrade(ctx), Paren(paren) => paren @@ -234,6 +234,62 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo } } +impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> for ast::CurPos { + fn downgrade(self, ctx: &mut Ctx) -> Result> { + fn byte_offset_to_line_col(content: &str, offset: usize) -> (u32, u32) { + let mut line = 1u32; + let mut col = 1u32; + + for (idx, ch) in content.char_indices() { + if idx >= offset { + break; + } + if ch == '\n' { + line += 1; + col = 1; + } else { + col += 1; + } + } + + (line, col) + } + + let span = self.syntax().text_range(); + let source = ctx.get_current_source(); + let (line, column) = byte_offset_to_line_col(&source.src, span.start().into()); + + let file_sym = ctx.intern_string("file"); + let line_sym = ctx.intern_string("line"); + let column_sym = ctx.intern_string("column"); + + let file: GhostRoMaybeThunkRef = ctx + .bump() + .alloc(GhostCell::new(MaybeThunk::Str(ctx.intern_string(source.get_name()))).into()); + let line = ctx + .bump() + .alloc(GhostCell::new(MaybeThunk::Int(i64::from(line))).into()); + let column = ctx + .bump() + .alloc(GhostCell::new(MaybeThunk::Int(i64::from(column))).into()); + + let map = { + let mut map = HashMap::new_in(ctx.bump()); + + map.insert(file_sym, (file, TextRange::default())); + map.insert(line_sym, (line, TextRange::default())); + map.insert(column_sym, (column, TextRange::default())); + + map + }; + + Ok(ctx.new_expr(Ir::AttrSet { + stcs: map, + dyns: Vec::new_in(ctx.bump()), + })) + } +} + impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> for ast::AttrSet { fn downgrade(self, ctx: &mut Ctx) -> Result> { let rec = self.rec_token().is_some(); @@ -266,8 +322,8 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> for ast::BinOp { fn downgrade(self, ctx: &mut Ctx) -> Result> { - use ast::BinOpKind as Kind; use BinOpKind::*; + use ast::BinOpKind as Kind; let span = self.syntax().text_range(); let lhs = self.lhs().require(ctx, span)?.downgrade(ctx)?; @@ -290,12 +346,20 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo Kind::Or => Or, Kind::PipeLeft => { let arg = ctx.maybe_thunk(rhs); - return Ok(ctx.new_expr(Ir::Call { func: lhs, arg, span })) - }, + return Ok(ctx.new_expr(Ir::Call { + func: lhs, + arg, + span, + })); + } Kind::PipeRight => { let arg = ctx.maybe_thunk(lhs); - return Ok(ctx.new_expr(Ir::Call { func: rhs, arg, span })) - }, + return Ok(ctx.new_expr(Ir::Call { + func: rhs, + arg, + span, + })); + } }; Ok(ctx.new_expr(Ir::BinOp { lhs, rhs, kind })) } diff --git a/fix-ir/src/lib.rs b/fix-ir/src/lib.rs index 1355f88..11d6600 100644 --- a/fix-ir/src/lib.rs +++ b/fix-ir/src/lib.rs @@ -215,7 +215,6 @@ pub enum Ir<'ir, R: RefExt<'ir> + ?Sized + 'ir> { thunks: Vec<'ir, (ThunkId, R::IrRef)>, }, MaybeThunk(R::MaybeThunkRef), - CurPos(TextRange), ReplBinding(StringId), ScopedImportBinding(StringId), } diff --git a/fix-vm/src/bytecode_reader.rs b/fix-vm/src/bytecode_reader.rs index cb0ee86..c483741 100644 --- a/fix-vm/src/bytecode_reader.rs +++ b/fix-vm/src/bytecode_reader.rs @@ -3,7 +3,7 @@ use fix_common::StringId; use num_enum::TryFromPrimitive; use string_interner::Symbol as _; -use crate::{AttrKeyData, OperandData, VmRuntimeCtx}; +use crate::{OperandData, VmRuntimeCtx}; pub(crate) struct BytecodeReader<'a> { bytecode: &'a [u8], @@ -132,18 +132,6 @@ impl<'a> BytecodeReader<'a> { } } - #[inline(always)] - pub(crate) fn read_attr_key_data(&mut self) -> crate::AttrKeyData { - use fix_codegen::AttrKeyType; - let tag = self.read_u8(); - let ty = AttrKeyType::try_from_primitive(tag) - .unwrap_or_else(|err| panic!("unknown key tag: {:#04x}", err.number)); - match ty { - AttrKeyType::Static => AttrKeyData::Static(self.read_string_id()), - AttrKeyType::Dynamic => AttrKeyData::Dynamic, - } - } - pub(crate) fn pc(&self) -> usize { self.pc } diff --git a/fix-vm/src/dispatch_tailcall.rs b/fix-vm/src/dispatch_tailcall.rs index 708fc1d..e6ebad1 100644 --- a/fix-vm/src/dispatch_tailcall.rs +++ b/fix-vm/src/dispatch_tailcall.rs @@ -193,7 +193,6 @@ tail_fn!(op_prepare_with, ()); tail_fn!(op_load_builtins, ()); tail_fn!(op_load_builtin, (reader)); -tail_fn!(op_mk_pos, (reader)); tail_fn!(op_load_repl_binding, (reader)); tail_fn!(op_load_scoped_binding, (reader)); @@ -286,7 +285,6 @@ table! { LoadBuiltins => op_load_builtins, LoadBuiltin => op_load_builtin, - MkPos => op_mk_pos, LoadReplBinding => op_load_repl_binding, LoadScopedBinding => op_load_scoped_binding, diff --git a/fix-vm/src/instructions/arithmetic.rs b/fix-vm/src/instructions/arithmetic.rs index 12dc9c7..cb735de 100644 --- a/fix-vm/src/instructions/arithmetic.rs +++ b/fix-vm/src/instructions/arithmetic.rs @@ -249,8 +249,8 @@ impl<'gc> crate::Vm<'gc> { return Ok(true); } if let (Some(a), Some(b)) = (lhs.as_gc::(), rhs.as_gc::()) { - let a = a.entries.borrow(); - let b = b.entries.borrow(); + let a = &a.entries; + let b = &b.entries; if a.len() != b.len() { return Ok(false); } diff --git a/fix-vm/src/instructions/builtins.rs b/fix-vm/src/instructions/builtins.rs index 7a122ac..92956b3 100644 --- a/fix-vm/src/instructions/builtins.rs +++ b/fix-vm/src/instructions/builtins.rs @@ -165,7 +165,7 @@ impl<'gc> Vm<'gc> { let e1 = self.peek_forced(1); let children: SmallVec<_> = if let Some(attrs) = e1.as_gc::() { - let attrs = attrs.entries.borrow(); + let attrs = &attrs.entries; if attrs.is_empty() { SmallVec::new() } else { @@ -243,7 +243,7 @@ impl<'gc> Vm<'gc> { let mut added: usize = 0; if let Some(attrs) = item.as_gc::() { - let attrs = attrs.entries.borrow(); + let attrs = &attrs.entries; #[allow(clippy::unwrap_used)] let seen = self.peek_forced(2).as_gc::>().unwrap(); if !self.is_value_in_seen(seen, item) { @@ -291,7 +291,7 @@ impl<'gc> Vm<'gc> { let val = self.peek_forced(0); let (count, has_children) = if let Some(attrs) = val.as_gc::() { - let len = attrs.entries.borrow().len(); + let len = attrs.entries.len(); (len, len > 0) } else if let Some(list) = val.as_gc::>() { let len = list.inner.borrow().len(); @@ -331,7 +331,7 @@ impl<'gc> Vm<'gc> { let val = self.peek_forced(2); let child = if let Some(attrs) = val.as_gc::() { - attrs.entries.borrow().get(idx as usize).map(|&(_, v)| v) + attrs.entries.get(idx as usize).map(|&(_, v)| v) } else if let Some(list) = val.as_gc::>() { list.inner.borrow().get(idx as usize).copied() } else { @@ -400,7 +400,7 @@ impl<'gc> Vm<'gc> { ))); } } - for &(key, _) in attrset.entries.borrow().iter() { + for &(key, _) in attrset.entries.iter() { let is_expected = pattern.required.contains(&key) || pattern.optional.contains(&key); if !is_expected { diff --git a/fix-vm/src/instructions/collections.rs b/fix-vm/src/instructions/collections.rs index 96497e1..66670f4 100644 --- a/fix-vm/src/instructions/collections.rs +++ b/fix-vm/src/instructions/collections.rs @@ -5,8 +5,7 @@ use smallvec::SmallVec; use crate::value::NixType; use crate::{ - AttrKeyData, AttrSet, BytecodeReader, List, OperandData, Step, StrictValue, Value, - VmRuntimeCtx, VmRuntimeCtxExt, + AttrSet, BytecodeReader, List, Step, StrictValue, Value, VmRuntimeCtx, VmRuntimeCtxExt, }; impl<'gc> crate::Vm<'gc> { @@ -17,25 +16,43 @@ impl<'gc> crate::Vm<'gc> { reader: &mut BytecodeReader<'_>, mc: &gc_arena::Mutation<'gc>, ) -> Step { - let count = reader.read_u32() as usize; - let mut entries: SmallVec<[AttrEntry; 4]> = SmallVec::with_capacity(count); - for _ in 0..count { - let key = reader.read_attr_key_data(); - let val = reader.read_operand_data(ctx); - let _span_id = reader.read_u32(); - entries.push(AttrEntry { key, val }); + let static_count = reader.read_u32() as usize; + let dynamic_count = reader.read_u32() as usize; + + for i in 0..dynamic_count { + let depth = dynamic_count - 1 - i; + self.force_slot_to_pc(depth, reader, mc, reader.inst_start_pc())?; } - let mut kv: SmallVec<[(crate::StringId, Value); 4]> = SmallVec::with_capacity(count); - for entry in &entries { - let key_sid = match &entry.key { - AttrKeyData::Static(sid) => *sid, - AttrKeyData::Dynamic => { - todo!() - } + + let mut dyn_keys: SmallVec<[crate::StringId; 2]> = SmallVec::with_capacity(dynamic_count); + for i in 0..dynamic_count { + let depth = dynamic_count - 1 - i; + let key_val = self.peek_forced(depth); + let key_sid = match ctx.get_string_id(key_val) { + Ok(id) => id, + Err(got) => return self.finish_type_err(NixType::String, got), }; - let val = entry.val.resolve(mc, self); - kv.push((key_sid, val)); + dyn_keys.push(key_sid); } + + self.stack.truncate(self.stack.len() - dynamic_count); + + let mut kv: SmallVec<[(crate::StringId, Value); 4]> = + SmallVec::with_capacity(static_count + dynamic_count); + + for _ in 0..static_count { + let key = reader.read_string_id(); + let val = reader.read_operand_data(ctx).resolve(mc, self); + let _span_id = reader.read_u32(); + kv.push((key, val)); + } + + for i in 0..dynamic_count { + let val = reader.read_operand_data(ctx).resolve(mc, self); + let _span_id = reader.read_u32(); + kv.push((dyn_keys[i], val)); + } + kv.sort_by_key(|(k, _)| *k); let attrs = Gc::new(mc, AttrSet::from_sorted_unchecked(kv)); self.push(Value::new_gc(attrs)); @@ -312,8 +329,3 @@ impl<'gc> crate::Vm<'gc> { Step::Continue(()) } } - -pub(crate) struct AttrEntry { - pub(crate) key: AttrKeyData, - pub(crate) val: OperandData, -} diff --git a/fix-vm/src/instructions/misc.rs b/fix-vm/src/instructions/misc.rs index f6c3cde..61377b2 100644 --- a/fix-vm/src/instructions/misc.rs +++ b/fix-vm/src/instructions/misc.rs @@ -22,12 +22,6 @@ impl<'gc> crate::Vm<'gc> { Step::Continue(()) } - #[inline(always)] - pub(crate) fn op_mk_pos(&mut self, reader: &mut BytecodeReader<'_>) -> Step { - let _span_id = reader.read_u32(); - todo!("MkPos"); - } - #[inline(always)] pub(crate) fn op_load_repl_binding(&mut self, reader: &mut BytecodeReader<'_>) -> Step { let _name = reader.read_string_id(); diff --git a/fix-vm/src/lib.rs b/fix-vm/src/lib.rs index cfb65cf..d6c1ee7 100644 --- a/fix-vm/src/lib.rs +++ b/fix-vm/src/lib.rs @@ -143,14 +143,14 @@ impl ConvertValueWithSeen for T { Value::String(ns.as_str().to_owned()) } else if let Some(attrs) = val.as_gc::() { let bits = val.to_bits(); - if attrs.entries.borrow().is_empty() { + if attrs.entries.is_empty() { return Value::AttrSet(Default::default()); } if !seen.insert(bits) { return Value::Repeated; } let mut map = std::collections::BTreeMap::new(); - for &(key, val) in attrs.entries.borrow().iter() { + for &(key, val) in attrs.entries.iter() { let key = self.resolve_string(key).to_owned(); let converted = self.convert_value_with_seen(val, seen); map.insert(fix_common::Symbol::from(key), converted); @@ -265,11 +265,6 @@ impl OperandData { } } -pub(crate) enum AttrKeyData { - Static(StringId), - Dynamic, -} - fn init_builtins<'gc>(mc: &Mutation<'gc>, ctx: &mut impl VmRuntimeCtx) -> Value<'gc> { let mut entries = SmallVec::with_capacity(BUILTINS.len()); @@ -471,7 +466,6 @@ impl<'gc> Vm<'gc> { match *state { ThunkState::Pending { ip, env, with_env } => { *state = ThunkState::Blackhole; - drop(state); self.call_stack.push(CallFrame { thunk: Some(thunk), stack_depth: depth, @@ -485,13 +479,21 @@ impl<'gc> Vm<'gc> { Step::Break(Break::Force) } ThunkState::Evaluated(v) => { - drop(state); self.replace(depth, v.relax()); Step::Continue(()) } - ThunkState::Apply { .. } => todo!("force apply"), + ThunkState::Apply { func, arg } => { + self.call_stack.push(CallFrame { + thunk: Some(thunk), + stack_depth: depth, + pc: resume_pc, + env: self.env, + with_env: self.with_env, + }); + self.push(func); + self.call(reader, mc, arg, resume_pc) + }, ThunkState::Blackhole => { - drop(state); self.finish_err(Error::eval_error("infinite recursion encountered")) } } @@ -676,7 +678,6 @@ impl<'gc> Vm<'gc> { LoadBuiltins => self.op_load_builtins(), LoadBuiltin => self.op_load_builtin(&mut reader), - MkPos => self.op_mk_pos(&mut reader), LoadReplBinding => self.op_load_repl_binding(&mut reader), LoadScopedBinding => self.op_load_scoped_binding(&mut reader), diff --git a/fix-vm/src/value.rs b/fix-vm/src/value.rs index a55c052..3740c57 100644 --- a/fix-vm/src/value.rs +++ b/fix-vm/src/value.rs @@ -435,78 +435,58 @@ impl fmt::Debug for NixString { #[derive(Collect, Debug, Default)] #[collect(no_drop)] pub(crate) struct AttrSet<'gc> { - pub(crate) entries: RefLock); 4]>>, -} - -impl<'gc> Unlock for AttrSet<'gc> { - type Unlocked = RefCell); 4]>>; - unsafe fn unlock_unchecked(&self) -> &Self::Unlocked { - unsafe { self.entries.unlock_unchecked() } - } + pub(crate) entries: SmallVec<[(StringId, Value<'gc>); 4]>, } impl<'gc> AttrSet<'gc> { pub(crate) fn from_sorted_unchecked(entries: SmallVec<[(StringId, Value<'gc>); 4]>) -> Self { debug_assert!(entries.is_sorted_by_key(|(key, _)| *key)); - Self { - entries: RefLock::new(entries), - } + Self { entries } } pub(crate) fn lookup(&self, key: StringId) -> Option> { - let entries = self.entries.borrow(); - entries + self.entries .binary_search_by_key(&key, |(k, _)| *k) .ok() - .map(|i| entries[i].1) + .map(|i| self.entries[i].1) } pub(crate) fn has(&self, key: StringId) -> bool { - self.entries - .borrow() - .binary_search_by_key(&key, |(k, _)| *k) - .is_ok() + self.entries.binary_search_by_key(&key, |(k, _)| *k).is_ok() } pub(crate) fn merge(&self, other: &Self, mc: &Mutation<'gc>) -> Gc<'gc, Self> { use std::cmp::Ordering::*; - let self_entries = self.entries.borrow(); - let other_entries = other.entries.borrow(); - debug_assert!(self_entries.is_sorted_by_key(|(key, _)| *key)); - debug_assert!(other_entries.is_sorted_by_key(|(key, _)| *key)); + debug_assert!(self.entries.is_sorted_by_key(|(key, _)| *key)); + debug_assert!(other.entries.is_sorted_by_key(|(key, _)| *key)); let mut entries = SmallVec::new(); let mut i = 0; let mut j = 0; - while i < self_entries.len() && j < other_entries.len() { - match self_entries[i].0.cmp(&other_entries[j].0) { + while i < self.entries.len() && j < other.entries.len() { + match self.entries[i].0.cmp(&other.entries[j].0) { Less => { - entries.push(self_entries[i]); + entries.push(self.entries[i]); i += 1; } Greater => { - entries.push(other_entries[j]); + entries.push(other.entries[j]); j += 1; } Equal => { - entries.push(other_entries[j]); + entries.push(other.entries[j]); i += 1; j += 1; } } } - entries.extend(other_entries[j..].iter().cloned()); - entries.extend(self_entries[i..].iter().cloned()); + entries.extend(other.entries[j..].iter().cloned()); + entries.extend(self.entries[i..].iter().cloned()); debug_assert!(entries.is_sorted_by_key(|(key, _)| *key)); - Gc::new( - mc, - AttrSet { - entries: RefLock::new(entries), - }, - ) + Gc::new(mc, AttrSet { entries }) } } diff --git a/fix/src/lib.rs b/fix/src/lib.rs index 0c99292..5b9c1c2 100644 --- a/fix/src/lib.rs +++ b/fix/src/lib.rs @@ -113,7 +113,7 @@ impl Evaluator { _expr: &str, _scope: &mut HashSet, ) -> Result { - todo!() + todo!("add_binding") } pub fn compile_bytecode(&mut self, source: Source) -> Result { @@ -248,7 +248,7 @@ impl<'a, R: VmRuntimeCtx> BytecodeContext for CompilerCtx<'a, R> { Float(x) => StaticValue::new_float(x), Bool(x) => StaticValue::new_inline(x), String(x) => StaticValue::new_inline(x), - Path(_) => todo!(), + Path(_) => todo!("path value type"), PrimOp { id, arity,