implement dynamic key; implement __curPos; other small changes
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
use fix_builtins::BuiltinId;
|
||||||
use num_enum::TryFromPrimitive;
|
use num_enum::TryFromPrimitive;
|
||||||
|
|
||||||
use crate::{AttrKeyType, InstructionPtr, Op, OperandType};
|
use crate::{InstructionPtr, Op, OperandType};
|
||||||
|
|
||||||
pub trait DisassemblerContext {
|
pub trait DisassemblerContext {
|
||||||
fn resolve_string(&self, id: u32) -> &str;
|
fn resolve_string(&self, id: u32) -> &str;
|
||||||
@@ -292,31 +293,30 @@ impl<'a, Ctx: DisassemblerContext> Disassembler<'a, Ctx> {
|
|||||||
("Call", "arg=?".into())
|
("Call", "arg=?".into())
|
||||||
},
|
},
|
||||||
Op::DispatchPrimOp => {
|
Op::DispatchPrimOp => {
|
||||||
todo!();
|
let id = BuiltinId::try_from_primitive(self.read_u8()).expect("invalid builtin id");
|
||||||
|
("DispatchPrimOp", format!("id={id:?}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
Op::MakeAttrs => {
|
Op::MakeAttrs => {
|
||||||
let count = self.read_u32();
|
let static_count = self.read_u32();
|
||||||
let mut args = format!("size={}", count);
|
let dynamic_count = self.read_u32();
|
||||||
for _ in 0..count {
|
let mut args = format!("static={} dynamic={}", static_count, dynamic_count);
|
||||||
let key_tag = self.read_u8();
|
|
||||||
let key_ty =
|
for _ in 0..static_count {
|
||||||
AttrKeyType::try_from_primitive(key_tag).expect("invalid attr key type");
|
|
||||||
match key_ty {
|
|
||||||
AttrKeyType::Static => {
|
|
||||||
let key_id = self.read_u32();
|
let key_id = self.read_u32();
|
||||||
let _ =
|
let _ = write!(args, " [{}={}", self.ctx.resolve_string(key_id), key_id);
|
||||||
write!(args, " [{}={}", self.ctx.resolve_string(key_id), key_id);
|
|
||||||
}
|
|
||||||
AttrKeyType::Dynamic => {
|
|
||||||
let _ = write!(args, " [dyn");
|
|
||||||
self.read_operand_data();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.read_operand_data();
|
self.read_operand_data();
|
||||||
let _span_id = self.read_u32();
|
let _span_id = self.read_u32();
|
||||||
args.push(']');
|
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)
|
("MakeAttrs", args)
|
||||||
}
|
}
|
||||||
Op::MakeEmptyAttrs => ("MakeEmptyAttrs", String::new()),
|
Op::MakeEmptyAttrs => ("MakeEmptyAttrs", String::new()),
|
||||||
@@ -442,10 +442,6 @@ impl<'a, Ctx: DisassemblerContext> Disassembler<'a, Ctx> {
|
|||||||
let id = self.read_u8();
|
let id = self.read_u8();
|
||||||
("LoadBuiltin", format!("id={}", id))
|
("LoadBuiltin", format!("id={}", id))
|
||||||
}
|
}
|
||||||
Op::MkPos => {
|
|
||||||
let span_id = self.read_u32();
|
|
||||||
("MkPos", format!("id={}", span_id))
|
|
||||||
}
|
|
||||||
Op::LoadReplBinding => {
|
Op::LoadReplBinding => {
|
||||||
let idx = self.read_u32();
|
let idx = self.read_u32();
|
||||||
let name = self.ctx.resolve_string(idx);
|
let name = self.ctx.resolve_string(idx);
|
||||||
|
|||||||
+7
-11
@@ -90,8 +90,6 @@ pub enum Op {
|
|||||||
LoadBuiltins,
|
LoadBuiltins,
|
||||||
LoadBuiltin,
|
LoadBuiltin,
|
||||||
|
|
||||||
MkPos,
|
|
||||||
|
|
||||||
LoadReplBinding,
|
LoadReplBinding,
|
||||||
LoadScopedBinding,
|
LoadScopedBinding,
|
||||||
|
|
||||||
@@ -646,11 +644,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
self.emit_str_id(raw_idx);
|
self.emit_str_id(raw_idx);
|
||||||
self.emit_u32(span_id);
|
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) => {
|
&Ir::ReplBinding(name) => {
|
||||||
self.emit_op(Op::LoadReplBinding);
|
self.emit_op(Op::LoadReplBinding);
|
||||||
self.emit_str_id(name);
|
self.emit_str_id(name);
|
||||||
@@ -879,19 +872,22 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
return;
|
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_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() {
|
for (&sym, &(val, span)) in stcs.iter() {
|
||||||
self.emit_u8(AttrKeyType::Static as u8);
|
|
||||||
self.emit_str_id(sym);
|
self.emit_str_id(sym);
|
||||||
self.emit_maybe_thunk(val);
|
self.emit_maybe_thunk(val);
|
||||||
let span_id = self.ctx.register_span(span);
|
let span_id = self.ctx.register_span(span);
|
||||||
self.emit_u32(span_id);
|
self.emit_u32(span_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
for &(_key, val, span) in dyns.iter() {
|
for &(_key, val, span) in dyns.iter() {
|
||||||
self.emit_u8(AttrKeyType::Dynamic as u8);
|
|
||||||
self.emit_maybe_thunk(val);
|
self.emit_maybe_thunk(val);
|
||||||
let span_id = self.ctx.register_span(span);
|
let span_id = self.ctx.register_span(span);
|
||||||
self.emit_u32(span_id);
|
self.emit_u32(span_id);
|
||||||
|
|||||||
+70
-6
@@ -98,7 +98,7 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo
|
|||||||
AttrSet(attrs) => attrs.downgrade(ctx),
|
AttrSet(attrs) => attrs.downgrade(ctx),
|
||||||
UnaryOp(op) => op.downgrade(ctx),
|
UnaryOp(op) => op.downgrade(ctx),
|
||||||
Ident(ident) => ident.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),
|
With(with) => with.downgrade(ctx),
|
||||||
HasAttr(has) => has.downgrade(ctx),
|
HasAttr(has) => has.downgrade(ctx),
|
||||||
Paren(paren) => paren
|
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<GhostRoIrRef<'id, 'ir>> {
|
||||||
|
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 {
|
impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> for ast::AttrSet {
|
||||||
fn downgrade(self, ctx: &mut Ctx) -> Result<GhostRoIrRef<'id, 'ir>> {
|
fn downgrade(self, ctx: &mut Ctx) -> Result<GhostRoIrRef<'id, 'ir>> {
|
||||||
let rec = self.rec_token().is_some();
|
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 {
|
impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> for ast::BinOp {
|
||||||
fn downgrade(self, ctx: &mut Ctx) -> Result<GhostRoIrRef<'id, 'ir>> {
|
fn downgrade(self, ctx: &mut Ctx) -> Result<GhostRoIrRef<'id, 'ir>> {
|
||||||
use ast::BinOpKind as Kind;
|
|
||||||
use BinOpKind::*;
|
use BinOpKind::*;
|
||||||
|
use ast::BinOpKind as Kind;
|
||||||
|
|
||||||
let span = self.syntax().text_range();
|
let span = self.syntax().text_range();
|
||||||
let lhs = self.lhs().require(ctx, span)?.downgrade(ctx)?;
|
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::Or => Or,
|
||||||
Kind::PipeLeft => {
|
Kind::PipeLeft => {
|
||||||
let arg = ctx.maybe_thunk(rhs);
|
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 => {
|
Kind::PipeRight => {
|
||||||
let arg = ctx.maybe_thunk(lhs);
|
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 }))
|
Ok(ctx.new_expr(Ir::BinOp { lhs, rhs, kind }))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,7 +215,6 @@ pub enum Ir<'ir, R: RefExt<'ir> + ?Sized + 'ir> {
|
|||||||
thunks: Vec<'ir, (ThunkId, R::IrRef)>,
|
thunks: Vec<'ir, (ThunkId, R::IrRef)>,
|
||||||
},
|
},
|
||||||
MaybeThunk(R::MaybeThunkRef),
|
MaybeThunk(R::MaybeThunkRef),
|
||||||
CurPos(TextRange),
|
|
||||||
ReplBinding(StringId),
|
ReplBinding(StringId),
|
||||||
ScopedImportBinding(StringId),
|
ScopedImportBinding(StringId),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use fix_common::StringId;
|
|||||||
use num_enum::TryFromPrimitive;
|
use num_enum::TryFromPrimitive;
|
||||||
use string_interner::Symbol as _;
|
use string_interner::Symbol as _;
|
||||||
|
|
||||||
use crate::{AttrKeyData, OperandData, VmRuntimeCtx};
|
use crate::{OperandData, VmRuntimeCtx};
|
||||||
|
|
||||||
pub(crate) struct BytecodeReader<'a> {
|
pub(crate) struct BytecodeReader<'a> {
|
||||||
bytecode: &'a [u8],
|
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 {
|
pub(crate) fn pc(&self) -> usize {
|
||||||
self.pc
|
self.pc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,7 +193,6 @@ tail_fn!(op_prepare_with, ());
|
|||||||
tail_fn!(op_load_builtins, ());
|
tail_fn!(op_load_builtins, ());
|
||||||
tail_fn!(op_load_builtin, (reader));
|
tail_fn!(op_load_builtin, (reader));
|
||||||
|
|
||||||
tail_fn!(op_mk_pos, (reader));
|
|
||||||
tail_fn!(op_load_repl_binding, (reader));
|
tail_fn!(op_load_repl_binding, (reader));
|
||||||
tail_fn!(op_load_scoped_binding, (reader));
|
tail_fn!(op_load_scoped_binding, (reader));
|
||||||
|
|
||||||
@@ -286,7 +285,6 @@ table! {
|
|||||||
LoadBuiltins => op_load_builtins,
|
LoadBuiltins => op_load_builtins,
|
||||||
LoadBuiltin => op_load_builtin,
|
LoadBuiltin => op_load_builtin,
|
||||||
|
|
||||||
MkPos => op_mk_pos,
|
|
||||||
LoadReplBinding => op_load_repl_binding,
|
LoadReplBinding => op_load_repl_binding,
|
||||||
LoadScopedBinding => op_load_scoped_binding,
|
LoadScopedBinding => op_load_scoped_binding,
|
||||||
|
|
||||||
|
|||||||
@@ -249,8 +249,8 @@ impl<'gc> crate::Vm<'gc> {
|
|||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
if let (Some(a), Some(b)) = (lhs.as_gc::<crate::AttrSet>(), rhs.as_gc::<crate::AttrSet>()) {
|
if let (Some(a), Some(b)) = (lhs.as_gc::<crate::AttrSet>(), rhs.as_gc::<crate::AttrSet>()) {
|
||||||
let a = a.entries.borrow();
|
let a = &a.entries;
|
||||||
let b = b.entries.borrow();
|
let b = &b.entries;
|
||||||
if a.len() != b.len() {
|
if a.len() != b.len() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ impl<'gc> Vm<'gc> {
|
|||||||
let e1 = self.peek_forced(1);
|
let e1 = self.peek_forced(1);
|
||||||
|
|
||||||
let children: SmallVec<_> = if let Some(attrs) = e1.as_gc::<AttrSet>() {
|
let children: SmallVec<_> = if let Some(attrs) = e1.as_gc::<AttrSet>() {
|
||||||
let attrs = attrs.entries.borrow();
|
let attrs = &attrs.entries;
|
||||||
if attrs.is_empty() {
|
if attrs.is_empty() {
|
||||||
SmallVec::new()
|
SmallVec::new()
|
||||||
} else {
|
} else {
|
||||||
@@ -243,7 +243,7 @@ impl<'gc> Vm<'gc> {
|
|||||||
|
|
||||||
let mut added: usize = 0;
|
let mut added: usize = 0;
|
||||||
if let Some(attrs) = item.as_gc::<AttrSet>() {
|
if let Some(attrs) = item.as_gc::<AttrSet>() {
|
||||||
let attrs = attrs.entries.borrow();
|
let attrs = &attrs.entries;
|
||||||
#[allow(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
let seen = self.peek_forced(2).as_gc::<List<'gc>>().unwrap();
|
let seen = self.peek_forced(2).as_gc::<List<'gc>>().unwrap();
|
||||||
if !self.is_value_in_seen(seen, item) {
|
if !self.is_value_in_seen(seen, item) {
|
||||||
@@ -291,7 +291,7 @@ impl<'gc> Vm<'gc> {
|
|||||||
let val = self.peek_forced(0);
|
let val = self.peek_forced(0);
|
||||||
|
|
||||||
let (count, has_children) = if let Some(attrs) = val.as_gc::<AttrSet>() {
|
let (count, has_children) = if let Some(attrs) = val.as_gc::<AttrSet>() {
|
||||||
let len = attrs.entries.borrow().len();
|
let len = attrs.entries.len();
|
||||||
(len, len > 0)
|
(len, len > 0)
|
||||||
} else if let Some(list) = val.as_gc::<List<'gc>>() {
|
} else if let Some(list) = val.as_gc::<List<'gc>>() {
|
||||||
let len = list.inner.borrow().len();
|
let len = list.inner.borrow().len();
|
||||||
@@ -331,7 +331,7 @@ impl<'gc> Vm<'gc> {
|
|||||||
|
|
||||||
let val = self.peek_forced(2);
|
let val = self.peek_forced(2);
|
||||||
let child = if let Some(attrs) = val.as_gc::<AttrSet>() {
|
let child = if let Some(attrs) = val.as_gc::<AttrSet>() {
|
||||||
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<'gc>>() {
|
} else if let Some(list) = val.as_gc::<List<'gc>>() {
|
||||||
list.inner.borrow().get(idx as usize).copied()
|
list.inner.borrow().get(idx as usize).copied()
|
||||||
} else {
|
} 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 =
|
let is_expected =
|
||||||
pattern.required.contains(&key) || pattern.optional.contains(&key);
|
pattern.required.contains(&key) || pattern.optional.contains(&key);
|
||||||
if !is_expected {
|
if !is_expected {
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ use smallvec::SmallVec;
|
|||||||
|
|
||||||
use crate::value::NixType;
|
use crate::value::NixType;
|
||||||
use crate::{
|
use crate::{
|
||||||
AttrKeyData, AttrSet, BytecodeReader, List, OperandData, Step, StrictValue, Value,
|
AttrSet, BytecodeReader, List, Step, StrictValue, Value, VmRuntimeCtx, VmRuntimeCtxExt,
|
||||||
VmRuntimeCtx, VmRuntimeCtxExt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'gc> crate::Vm<'gc> {
|
impl<'gc> crate::Vm<'gc> {
|
||||||
@@ -17,25 +16,43 @@ impl<'gc> crate::Vm<'gc> {
|
|||||||
reader: &mut BytecodeReader<'_>,
|
reader: &mut BytecodeReader<'_>,
|
||||||
mc: &gc_arena::Mutation<'gc>,
|
mc: &gc_arena::Mutation<'gc>,
|
||||||
) -> Step {
|
) -> Step {
|
||||||
let count = reader.read_u32() as usize;
|
let static_count = reader.read_u32() as usize;
|
||||||
let mut entries: SmallVec<[AttrEntry; 4]> = SmallVec::with_capacity(count);
|
let dynamic_count = reader.read_u32() as usize;
|
||||||
for _ in 0..count {
|
|
||||||
let key = reader.read_attr_key_data();
|
for i in 0..dynamic_count {
|
||||||
let val = reader.read_operand_data(ctx);
|
let depth = dynamic_count - 1 - i;
|
||||||
let _span_id = reader.read_u32();
|
self.force_slot_to_pc(depth, reader, mc, reader.inst_start_pc())?;
|
||||||
entries.push(AttrEntry { key, val });
|
|
||||||
}
|
|
||||||
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);
|
dyn_keys.push(key_sid);
|
||||||
kv.push((key_sid, val));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
kv.sort_by_key(|(k, _)| *k);
|
||||||
let attrs = Gc::new(mc, AttrSet::from_sorted_unchecked(kv));
|
let attrs = Gc::new(mc, AttrSet::from_sorted_unchecked(kv));
|
||||||
self.push(Value::new_gc(attrs));
|
self.push(Value::new_gc(attrs));
|
||||||
@@ -312,8 +329,3 @@ impl<'gc> crate::Vm<'gc> {
|
|||||||
Step::Continue(())
|
Step::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct AttrEntry {
|
|
||||||
pub(crate) key: AttrKeyData,
|
|
||||||
pub(crate) val: OperandData,
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -22,12 +22,6 @@ impl<'gc> crate::Vm<'gc> {
|
|||||||
Step::Continue(())
|
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)]
|
#[inline(always)]
|
||||||
pub(crate) fn op_load_repl_binding(&mut self, reader: &mut BytecodeReader<'_>) -> Step {
|
pub(crate) fn op_load_repl_binding(&mut self, reader: &mut BytecodeReader<'_>) -> Step {
|
||||||
let _name = reader.read_string_id();
|
let _name = reader.read_string_id();
|
||||||
|
|||||||
+13
-12
@@ -143,14 +143,14 @@ impl<T: VmRuntimeCtx> ConvertValueWithSeen for T {
|
|||||||
Value::String(ns.as_str().to_owned())
|
Value::String(ns.as_str().to_owned())
|
||||||
} else if let Some(attrs) = val.as_gc::<AttrSet>() {
|
} else if let Some(attrs) = val.as_gc::<AttrSet>() {
|
||||||
let bits = val.to_bits();
|
let bits = val.to_bits();
|
||||||
if attrs.entries.borrow().is_empty() {
|
if attrs.entries.is_empty() {
|
||||||
return Value::AttrSet(Default::default());
|
return Value::AttrSet(Default::default());
|
||||||
}
|
}
|
||||||
if !seen.insert(bits) {
|
if !seen.insert(bits) {
|
||||||
return Value::Repeated;
|
return Value::Repeated;
|
||||||
}
|
}
|
||||||
let mut map = std::collections::BTreeMap::new();
|
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 key = self.resolve_string(key).to_owned();
|
||||||
let converted = self.convert_value_with_seen(val, seen);
|
let converted = self.convert_value_with_seen(val, seen);
|
||||||
map.insert(fix_common::Symbol::from(key), converted);
|
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> {
|
fn init_builtins<'gc>(mc: &Mutation<'gc>, ctx: &mut impl VmRuntimeCtx) -> Value<'gc> {
|
||||||
let mut entries = SmallVec::with_capacity(BUILTINS.len());
|
let mut entries = SmallVec::with_capacity(BUILTINS.len());
|
||||||
|
|
||||||
@@ -471,7 +466,6 @@ impl<'gc> Vm<'gc> {
|
|||||||
match *state {
|
match *state {
|
||||||
ThunkState::Pending { ip, env, with_env } => {
|
ThunkState::Pending { ip, env, with_env } => {
|
||||||
*state = ThunkState::Blackhole;
|
*state = ThunkState::Blackhole;
|
||||||
drop(state);
|
|
||||||
self.call_stack.push(CallFrame {
|
self.call_stack.push(CallFrame {
|
||||||
thunk: Some(thunk),
|
thunk: Some(thunk),
|
||||||
stack_depth: depth,
|
stack_depth: depth,
|
||||||
@@ -485,13 +479,21 @@ impl<'gc> Vm<'gc> {
|
|||||||
Step::Break(Break::Force)
|
Step::Break(Break::Force)
|
||||||
}
|
}
|
||||||
ThunkState::Evaluated(v) => {
|
ThunkState::Evaluated(v) => {
|
||||||
drop(state);
|
|
||||||
self.replace(depth, v.relax());
|
self.replace(depth, v.relax());
|
||||||
Step::Continue(())
|
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 => {
|
ThunkState::Blackhole => {
|
||||||
drop(state);
|
|
||||||
self.finish_err(Error::eval_error("infinite recursion encountered"))
|
self.finish_err(Error::eval_error("infinite recursion encountered"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -676,7 +678,6 @@ impl<'gc> Vm<'gc> {
|
|||||||
LoadBuiltins => self.op_load_builtins(),
|
LoadBuiltins => self.op_load_builtins(),
|
||||||
LoadBuiltin => self.op_load_builtin(&mut reader),
|
LoadBuiltin => self.op_load_builtin(&mut reader),
|
||||||
|
|
||||||
MkPos => self.op_mk_pos(&mut reader),
|
|
||||||
LoadReplBinding => self.op_load_repl_binding(&mut reader),
|
LoadReplBinding => self.op_load_repl_binding(&mut reader),
|
||||||
LoadScopedBinding => self.op_load_scoped_binding(&mut reader),
|
LoadScopedBinding => self.op_load_scoped_binding(&mut reader),
|
||||||
|
|
||||||
|
|||||||
+15
-35
@@ -435,78 +435,58 @@ impl fmt::Debug for NixString {
|
|||||||
#[derive(Collect, Debug, Default)]
|
#[derive(Collect, Debug, Default)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
pub(crate) struct AttrSet<'gc> {
|
pub(crate) struct AttrSet<'gc> {
|
||||||
pub(crate) entries: RefLock<SmallVec<[(StringId, Value<'gc>); 4]>>,
|
pub(crate) entries: SmallVec<[(StringId, Value<'gc>); 4]>,
|
||||||
}
|
|
||||||
|
|
||||||
impl<'gc> Unlock for AttrSet<'gc> {
|
|
||||||
type Unlocked = RefCell<SmallVec<[(StringId, Value<'gc>); 4]>>;
|
|
||||||
unsafe fn unlock_unchecked(&self) -> &Self::Unlocked {
|
|
||||||
unsafe { self.entries.unlock_unchecked() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> AttrSet<'gc> {
|
impl<'gc> AttrSet<'gc> {
|
||||||
pub(crate) fn from_sorted_unchecked(entries: SmallVec<[(StringId, Value<'gc>); 4]>) -> Self {
|
pub(crate) fn from_sorted_unchecked(entries: SmallVec<[(StringId, Value<'gc>); 4]>) -> Self {
|
||||||
debug_assert!(entries.is_sorted_by_key(|(key, _)| *key));
|
debug_assert!(entries.is_sorted_by_key(|(key, _)| *key));
|
||||||
Self {
|
Self { entries }
|
||||||
entries: RefLock::new(entries),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn lookup(&self, key: StringId) -> Option<Value<'gc>> {
|
pub(crate) fn lookup(&self, key: StringId) -> Option<Value<'gc>> {
|
||||||
let entries = self.entries.borrow();
|
self.entries
|
||||||
entries
|
|
||||||
.binary_search_by_key(&key, |(k, _)| *k)
|
.binary_search_by_key(&key, |(k, _)| *k)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|i| entries[i].1)
|
.map(|i| self.entries[i].1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn has(&self, key: StringId) -> bool {
|
pub(crate) fn has(&self, key: StringId) -> bool {
|
||||||
self.entries
|
self.entries.binary_search_by_key(&key, |(k, _)| *k).is_ok()
|
||||||
.borrow()
|
|
||||||
.binary_search_by_key(&key, |(k, _)| *k)
|
|
||||||
.is_ok()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn merge(&self, other: &Self, mc: &Mutation<'gc>) -> Gc<'gc, Self> {
|
pub(crate) fn merge(&self, other: &Self, mc: &Mutation<'gc>) -> Gc<'gc, Self> {
|
||||||
use std::cmp::Ordering::*;
|
use std::cmp::Ordering::*;
|
||||||
|
|
||||||
let self_entries = self.entries.borrow();
|
debug_assert!(self.entries.is_sorted_by_key(|(key, _)| *key));
|
||||||
let other_entries = other.entries.borrow();
|
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 entries = SmallVec::new();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut j = 0;
|
let mut j = 0;
|
||||||
while i < self_entries.len() && j < other_entries.len() {
|
while i < self.entries.len() && j < other.entries.len() {
|
||||||
match self_entries[i].0.cmp(&other_entries[j].0) {
|
match self.entries[i].0.cmp(&other.entries[j].0) {
|
||||||
Less => {
|
Less => {
|
||||||
entries.push(self_entries[i]);
|
entries.push(self.entries[i]);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
Greater => {
|
Greater => {
|
||||||
entries.push(other_entries[j]);
|
entries.push(other.entries[j]);
|
||||||
j += 1;
|
j += 1;
|
||||||
}
|
}
|
||||||
Equal => {
|
Equal => {
|
||||||
entries.push(other_entries[j]);
|
entries.push(other.entries[j]);
|
||||||
i += 1;
|
i += 1;
|
||||||
j += 1;
|
j += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entries.extend(other_entries[j..].iter().cloned());
|
entries.extend(other.entries[j..].iter().cloned());
|
||||||
entries.extend(self_entries[i..].iter().cloned());
|
entries.extend(self.entries[i..].iter().cloned());
|
||||||
|
|
||||||
debug_assert!(entries.is_sorted_by_key(|(key, _)| *key));
|
debug_assert!(entries.is_sorted_by_key(|(key, _)| *key));
|
||||||
|
|
||||||
Gc::new(
|
Gc::new(mc, AttrSet { entries })
|
||||||
mc,
|
|
||||||
AttrSet {
|
|
||||||
entries: RefLock::new(entries),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -113,7 +113,7 @@ impl Evaluator {
|
|||||||
_expr: &str,
|
_expr: &str,
|
||||||
_scope: &mut HashSet<StringId>,
|
_scope: &mut HashSet<StringId>,
|
||||||
) -> Result<fix_common::Value> {
|
) -> Result<fix_common::Value> {
|
||||||
todo!()
|
todo!("add_binding")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_bytecode(&mut self, source: Source) -> Result<InstructionPtr> {
|
pub fn compile_bytecode(&mut self, source: Source) -> Result<InstructionPtr> {
|
||||||
@@ -248,7 +248,7 @@ impl<'a, R: VmRuntimeCtx> BytecodeContext for CompilerCtx<'a, R> {
|
|||||||
Float(x) => StaticValue::new_float(x),
|
Float(x) => StaticValue::new_float(x),
|
||||||
Bool(x) => StaticValue::new_inline(x),
|
Bool(x) => StaticValue::new_inline(x),
|
||||||
String(x) => StaticValue::new_inline(x),
|
String(x) => StaticValue::new_inline(x),
|
||||||
Path(_) => todo!(),
|
Path(_) => todo!("path value type"),
|
||||||
PrimOp {
|
PrimOp {
|
||||||
id,
|
id,
|
||||||
arity,
|
arity,
|
||||||
|
|||||||
Reference in New Issue
Block a user