Compare commits
5 Commits
b1b886229b
...
9d4c37950e
| Author | SHA1 | Date | |
|---|---|---|---|
|
9d4c37950e
|
|||
|
e34cfc7add
|
|||
|
9983458b31
|
|||
|
8e67f9f636
|
|||
|
d90fd8d681
|
Generated
+10
-2
@@ -258,6 +258,15 @@ version = "1.0.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "3.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "countme"
|
name = "countme"
|
||||||
version = "3.0.1"
|
version = "3.0.1"
|
||||||
@@ -451,7 +460,6 @@ dependencies = [
|
|||||||
"mimalloc",
|
"mimalloc",
|
||||||
"rnix",
|
"rnix",
|
||||||
"rustyline",
|
"rustyline",
|
||||||
"smallvec",
|
|
||||||
"string-interner",
|
"string-interner",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"test-log",
|
"test-log",
|
||||||
@@ -472,10 +480,10 @@ dependencies = [
|
|||||||
name = "fix-codegen"
|
name = "fix-codegen"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"colored",
|
||||||
"fix-builtins",
|
"fix-builtins",
|
||||||
"fix-common",
|
"fix-common",
|
||||||
"fix-ir",
|
"fix-ir",
|
||||||
"gc-arena",
|
|
||||||
"hashbrown 0.16.1",
|
"hashbrown 0.16.1",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"rnix",
|
"rnix",
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ members = [
|
|||||||
inherits = "release"
|
inherits = "release"
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
|
[profile.lto]
|
||||||
|
inherits = "release"
|
||||||
|
lto = true
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
bumpalo = { version = "3.20", features = [
|
bumpalo = { version = "3.20", features = [
|
||||||
"allocator-api2",
|
"allocator-api2",
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gc-arena = { workspace = true }
|
|
||||||
hashbrown = { workspace = true }
|
hashbrown = { workspace = true }
|
||||||
num_enum = { workspace = true }
|
num_enum = { workspace = true }
|
||||||
rnix = { workspace = true }
|
rnix = { workspace = true }
|
||||||
string-interner = { workspace = true }
|
string-interner = { workspace = true }
|
||||||
|
colored = "3.1.1"
|
||||||
|
|
||||||
fix-builtins = { path = "../fix-builtins" }
|
fix-builtins = { path = "../fix-builtins" }
|
||||||
fix-common = { path = "../fix-common" }
|
fix-common = { path = "../fix-common" }
|
||||||
|
|||||||
@@ -0,0 +1,366 @@
|
|||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
use colored::Colorize;
|
||||||
|
use num_enum::TryFromPrimitive;
|
||||||
|
|
||||||
|
use crate::{InstructionPtr, Op};
|
||||||
|
|
||||||
|
pub trait DisassemblerContext {
|
||||||
|
fn resolve_string(&self, id: u32) -> &str;
|
||||||
|
fn get_code(&self) -> &[u8];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Disassembler<'a, Ctx> {
|
||||||
|
code: &'a [u8],
|
||||||
|
ctx: &'a Ctx,
|
||||||
|
pc: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Ctx: DisassemblerContext> Disassembler<'a, Ctx> {
|
||||||
|
pub fn new(ip: InstructionPtr, ctx: &'a Ctx) -> Self {
|
||||||
|
Self {
|
||||||
|
code: ctx.get_code(),
|
||||||
|
ctx,
|
||||||
|
pc: ip.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u8(&mut self) -> u8 {
|
||||||
|
let b = self.code[self.pc];
|
||||||
|
self.pc += 1;
|
||||||
|
b
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u16(&mut self) -> u16 {
|
||||||
|
let bytes = self.code[self.pc..self.pc + 2]
|
||||||
|
.try_into()
|
||||||
|
.expect("no enough bytes");
|
||||||
|
self.pc += 2;
|
||||||
|
u16::from_le_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u32(&mut self) -> u32 {
|
||||||
|
let bytes = self.code[self.pc..self.pc + 4]
|
||||||
|
.try_into()
|
||||||
|
.expect("no enough bytes");
|
||||||
|
self.pc += 4;
|
||||||
|
u32::from_le_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_i32(&mut self) -> i32 {
|
||||||
|
let bytes = self.code[self.pc..self.pc + 4]
|
||||||
|
.try_into()
|
||||||
|
.expect("no enough bytes");
|
||||||
|
self.pc += 4;
|
||||||
|
i32::from_le_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_i64(&mut self) -> i64 {
|
||||||
|
let bytes = self.code[self.pc..self.pc + 8]
|
||||||
|
.try_into()
|
||||||
|
.expect("no enough bytes");
|
||||||
|
self.pc += 8;
|
||||||
|
i64::from_le_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_f64(&mut self) -> f64 {
|
||||||
|
let bytes = self.code[self.pc..self.pc + 8]
|
||||||
|
.try_into()
|
||||||
|
.expect("no enough bytes");
|
||||||
|
self.pc += 8;
|
||||||
|
f64::from_le_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disassemble(&mut self) -> String {
|
||||||
|
self.disassemble_impl(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disassemble_colored(&mut self) -> String {
|
||||||
|
self.disassemble_impl(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disassemble_impl(&mut self, color: bool) -> String {
|
||||||
|
let mut out = String::new();
|
||||||
|
if color {
|
||||||
|
let _ = writeln!(out, "{}", "=== Bytecode Disassembly ===".bold().white());
|
||||||
|
let _ = writeln!(
|
||||||
|
out,
|
||||||
|
"{} {}",
|
||||||
|
"Length:".white(),
|
||||||
|
format!("{} bytes", self.code.len()).cyan()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let _ = writeln!(out, "=== Bytecode Disassembly ===");
|
||||||
|
let _ = writeln!(out, "Length: {} bytes", self.code.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
while self.pc < self.code.len() {
|
||||||
|
let start_pos = self.pc;
|
||||||
|
let op_byte = self.read_u8();
|
||||||
|
let (mnemonic, args) = self.decode_instruction(op_byte, start_pos);
|
||||||
|
|
||||||
|
let bytes_slice = &self.code[start_pos + 1..self.pc];
|
||||||
|
let mut chunks = bytes_slice.chunks(4);
|
||||||
|
|
||||||
|
let first_chunk = chunks.next().unwrap_or(&[]);
|
||||||
|
let bytes_str = {
|
||||||
|
let mut temp = format!("{:02x}", self.code[start_pos]);
|
||||||
|
for b in first_chunk {
|
||||||
|
let _ = write!(&mut temp, " {:02x}", b);
|
||||||
|
}
|
||||||
|
temp
|
||||||
|
};
|
||||||
|
|
||||||
|
if color {
|
||||||
|
let sep = if args.is_empty() { "" } else { " " };
|
||||||
|
let _ = writeln!(
|
||||||
|
out,
|
||||||
|
"{} {:<14} | {}{}{}",
|
||||||
|
format!("{:04x}", start_pos).dimmed(),
|
||||||
|
bytes_str.green(),
|
||||||
|
mnemonic.yellow().bold(),
|
||||||
|
sep,
|
||||||
|
args.cyan()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let op_str = if args.is_empty() {
|
||||||
|
mnemonic.to_string()
|
||||||
|
} else {
|
||||||
|
format!("{} {}", mnemonic, args)
|
||||||
|
};
|
||||||
|
let _ = writeln!(out, "{:04x} {:<14} | {}", start_pos, bytes_str, op_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
for chunk in chunks {
|
||||||
|
let bytes_str = {
|
||||||
|
let mut temp = String::from(" ");
|
||||||
|
for b in chunk {
|
||||||
|
let _ = write!(&mut temp, " {:02x}", b);
|
||||||
|
}
|
||||||
|
temp
|
||||||
|
};
|
||||||
|
|
||||||
|
let extra_width = if start_pos > 0 {
|
||||||
|
start_pos.ilog2() >> 4
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
if color {
|
||||||
|
let _ = write!(out, " ");
|
||||||
|
for _ in 0..extra_width {
|
||||||
|
let _ = write!(out, " ");
|
||||||
|
}
|
||||||
|
let _ = writeln!(out, " {:<14} |", bytes_str.green());
|
||||||
|
} else {
|
||||||
|
let _ = write!(out, " ");
|
||||||
|
for _ in 0..extra_width {
|
||||||
|
let _ = write!(out, " ");
|
||||||
|
}
|
||||||
|
let _ = writeln!(out, " {:<14} |", bytes_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_instruction(&mut self, op_byte: u8, current_pc: usize) -> (&'static str, String) {
|
||||||
|
let op = Op::try_from_primitive(op_byte).expect("invalid op code");
|
||||||
|
|
||||||
|
match op {
|
||||||
|
Op::PushSmi => {
|
||||||
|
let val = self.read_i32();
|
||||||
|
("PushSmi", format!("{}", val))
|
||||||
|
}
|
||||||
|
Op::PushBigInt => {
|
||||||
|
let val = self.read_i64();
|
||||||
|
("PushBigInt", format!("{}", val))
|
||||||
|
}
|
||||||
|
Op::PushFloat => {
|
||||||
|
let val = self.read_f64();
|
||||||
|
("PushFloat", format!("{}", val))
|
||||||
|
}
|
||||||
|
Op::PushString => {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
let s = self.ctx.resolve_string(idx);
|
||||||
|
let len = s.len();
|
||||||
|
let mut s_fmt = format!("{:?}", s);
|
||||||
|
if s_fmt.len() > 60 {
|
||||||
|
s_fmt.truncate(57);
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
write!(s_fmt, "...\" (total {len} bytes)").unwrap();
|
||||||
|
}
|
||||||
|
("PushString", format!("@{} {}", idx, s_fmt))
|
||||||
|
}
|
||||||
|
Op::PushNull => ("PushNull", String::new()),
|
||||||
|
Op::PushTrue => ("PushTrue", String::new()),
|
||||||
|
Op::PushFalse => ("PushFalse", String::new()),
|
||||||
|
|
||||||
|
Op::LoadLocal => {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
("LoadLocal", format!("[{}]", idx))
|
||||||
|
}
|
||||||
|
Op::LoadOuter => {
|
||||||
|
let depth = self.read_u8();
|
||||||
|
let idx = self.read_u32();
|
||||||
|
("LoadOuter", format!("depth={} [{}]", depth, idx))
|
||||||
|
}
|
||||||
|
Op::StoreLocal => {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
("StoreLocal", format!("[{}]", idx))
|
||||||
|
}
|
||||||
|
Op::AllocLocals => {
|
||||||
|
let count = self.read_u32();
|
||||||
|
("AllocLocals", format!("count={}", count))
|
||||||
|
}
|
||||||
|
|
||||||
|
Op::MakeThunk => {
|
||||||
|
let offset = self.read_u32();
|
||||||
|
("MakeThunk", format!("-> {:04x}", offset))
|
||||||
|
}
|
||||||
|
Op::MakeClosure => {
|
||||||
|
let offset = self.read_u32();
|
||||||
|
let slots = self.read_u32();
|
||||||
|
("MakeClosure", format!("-> {:04x} slots={}", offset, slots))
|
||||||
|
}
|
||||||
|
Op::MakePatternClosure => {
|
||||||
|
let offset = self.read_u32();
|
||||||
|
let slots = self.read_u32();
|
||||||
|
let req_count = self.read_u16();
|
||||||
|
let opt_count = self.read_u16();
|
||||||
|
let ellipsis = self.read_u8() != 0;
|
||||||
|
|
||||||
|
let mut arg_str = format!(
|
||||||
|
"-> {:04x} slots={} req={} opt={} ...={})",
|
||||||
|
offset, slots, req_count, opt_count, ellipsis
|
||||||
|
);
|
||||||
|
|
||||||
|
arg_str.push_str(" Args=[");
|
||||||
|
for _ in 0..req_count {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
arg_str.push_str(&format!("Req({}) ", self.ctx.resolve_string(idx)));
|
||||||
|
}
|
||||||
|
for _ in 0..opt_count {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
arg_str.push_str(&format!("Opt({}) ", self.ctx.resolve_string(idx)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let total_args = req_count + opt_count;
|
||||||
|
for _ in 0..total_args {
|
||||||
|
let _name_idx = self.read_u32();
|
||||||
|
let _span_id = self.read_u32();
|
||||||
|
}
|
||||||
|
arg_str.push(']');
|
||||||
|
|
||||||
|
("MakePatternClosure", arg_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
Op::Call => ("Call", String::new()),
|
||||||
|
|
||||||
|
Op::MakeAttrs => {
|
||||||
|
let count = self.read_u32();
|
||||||
|
("MakeAttrs", format!("size={}", count))
|
||||||
|
}
|
||||||
|
Op::MakeEmptyAttrs => ("MakeEmptyAttrs", String::new()),
|
||||||
|
|
||||||
|
Op::Select => {
|
||||||
|
let path_len = self.read_u16();
|
||||||
|
let span_id = self.read_u32();
|
||||||
|
("Select", format!("path_len={} span={}", path_len, span_id))
|
||||||
|
}
|
||||||
|
Op::SelectDefault => {
|
||||||
|
let path_len = self.read_u16();
|
||||||
|
let span_id = self.read_u32();
|
||||||
|
(
|
||||||
|
"SelectDefault",
|
||||||
|
format!("path_len={} span={}", path_len, span_id),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Op::HasAttr => {
|
||||||
|
let path_len = self.read_u16();
|
||||||
|
("HasAttr", format!("path_len={}", path_len))
|
||||||
|
}
|
||||||
|
|
||||||
|
Op::MakeList => {
|
||||||
|
let count = self.read_u32();
|
||||||
|
("MakeList", format!("size={}", count))
|
||||||
|
}
|
||||||
|
Op::MakeEmptyList => ("MakeEmptyList", String::new()),
|
||||||
|
|
||||||
|
Op::OpAdd => ("OpAdd", String::new()),
|
||||||
|
Op::OpSub => ("OpSub", String::new()),
|
||||||
|
Op::OpMul => ("OpMul", String::new()),
|
||||||
|
Op::OpDiv => ("OpDiv", String::new()),
|
||||||
|
Op::OpEq => ("OpEq", String::new()),
|
||||||
|
Op::OpNeq => ("OpNeq", String::new()),
|
||||||
|
Op::OpLt => ("OpLt", String::new()),
|
||||||
|
Op::OpGt => ("OpGt", String::new()),
|
||||||
|
Op::OpLeq => ("OpLeq", String::new()),
|
||||||
|
Op::OpGeq => ("OpGeq", String::new()),
|
||||||
|
Op::OpConcat => ("OpConcat", String::new()),
|
||||||
|
Op::OpUpdate => ("OpUpdate", String::new()),
|
||||||
|
Op::OpNeg => ("OpNeg", String::new()),
|
||||||
|
Op::OpNot => ("OpNot", String::new()),
|
||||||
|
|
||||||
|
Op::JumpIfFalse => {
|
||||||
|
let offset = self.read_i32();
|
||||||
|
let target = (current_pc as isize + 1 + 4 + offset as isize) as usize;
|
||||||
|
(
|
||||||
|
"JumpIfFalse",
|
||||||
|
format!("-> {:04x} offset={}", target, offset),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Op::JumpIfTrue => {
|
||||||
|
let offset = self.read_i32();
|
||||||
|
let target = (current_pc as isize + 1 + 4 + offset as isize) as usize;
|
||||||
|
("JumpIfTrue", format!("-> {:04x} offset={}", target, offset))
|
||||||
|
}
|
||||||
|
Op::Jump => {
|
||||||
|
let offset = self.read_i32();
|
||||||
|
let target = (current_pc as isize + 1 + 4 + offset as isize) as usize;
|
||||||
|
("Jump", format!("-> {:04x} offset={}", target, offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
Op::ConcatStrings => {
|
||||||
|
let count = self.read_u16();
|
||||||
|
let force = self.read_u8();
|
||||||
|
("ConcatStrings", format!("count={} force={}", count, force))
|
||||||
|
}
|
||||||
|
Op::ResolvePath => ("ResolvePath", String::new()),
|
||||||
|
Op::Assert => {
|
||||||
|
let raw_idx = self.read_u32();
|
||||||
|
let span_id = self.read_u32();
|
||||||
|
("Assert", format!("text_id={} span={}", raw_idx, span_id))
|
||||||
|
}
|
||||||
|
Op::PushWith => ("PushWith", String::new()),
|
||||||
|
Op::PopWith => ("PopWith", String::new()),
|
||||||
|
Op::WithLookup => {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
let name = self.ctx.resolve_string(idx);
|
||||||
|
("WithLookup", format!("{:?}", name))
|
||||||
|
}
|
||||||
|
|
||||||
|
Op::LoadBuiltins => ("LoadBuiltins", String::new()),
|
||||||
|
Op::LoadBuiltin => {
|
||||||
|
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);
|
||||||
|
("LoadReplBinding", format!("{:?}", name))
|
||||||
|
}
|
||||||
|
Op::LoadScopedBinding => {
|
||||||
|
let idx = self.read_u32();
|
||||||
|
let name = self.ctx.resolve_string(idx);
|
||||||
|
("LoadScopedBinding", format!("{:?}", name))
|
||||||
|
}
|
||||||
|
Op::Return => ("Return", String::new()),
|
||||||
|
Op::Illegal => ("Illegal", String::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+48
-88
@@ -1,13 +1,15 @@
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use fix_builtins::{BUILTINS, BuiltinId};
|
use fix_builtins::BuiltinId;
|
||||||
use fix_common::StringId;
|
use fix_common::StringId;
|
||||||
use fix_ir::{Attr, BinOpKind, Ir, Param, RawIrRef, ThunkId, UnOpKind};
|
use fix_ir::{Attr, BinOpKind, Ir, MaybeThunk, Param, RawIrRef, ThunkId, UnOpKind};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use num_enum::TryFromPrimitive;
|
use num_enum::TryFromPrimitive;
|
||||||
use rnix::TextRange;
|
use rnix::TextRange;
|
||||||
use string_interner::Symbol as _;
|
use string_interner::Symbol as _;
|
||||||
|
|
||||||
|
pub mod disassembler;
|
||||||
|
|
||||||
pub struct InstructionPtr(pub usize);
|
pub struct InstructionPtr(pub usize);
|
||||||
|
|
||||||
pub trait BytecodeContext {
|
pub trait BytecodeContext {
|
||||||
@@ -149,40 +151,34 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn classify_value(&mut self, ir: RawIrRef<'_>) -> InlineOperand {
|
fn inline_maybe_thunk(&mut self, val: MaybeThunk) -> InlineOperand {
|
||||||
match ir.deref() {
|
use MaybeThunk::*;
|
||||||
&Ir::Int(x) => {
|
match val {
|
||||||
|
Int(x) => {
|
||||||
if x <= i32::MAX as i64 {
|
if x <= i32::MAX as i64 {
|
||||||
InlineOperand::Const(Const::Smi(x as i32))
|
InlineOperand::Const(Const::Smi(x as i32))
|
||||||
} else {
|
} else {
|
||||||
InlineOperand::BigInt(x)
|
InlineOperand::BigInt(x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Ir::Float(x) => InlineOperand::Const(Const::Float(x)),
|
Float(x) => InlineOperand::Const(Const::Float(x)),
|
||||||
&Ir::Bool(b) => InlineOperand::Const(Const::Bool(b)),
|
Bool(b) => InlineOperand::Const(Const::Bool(b)),
|
||||||
Ir::Null => InlineOperand::Const(Const::Null),
|
Null => InlineOperand::Const(Const::Null),
|
||||||
Ir::Str(s) => {
|
Str(id) => InlineOperand::Const(Const::String(id)),
|
||||||
let sid = self.ctx.intern_string(s.deref());
|
Thunk(id) => {
|
||||||
InlineOperand::Const(Const::String(sid))
|
|
||||||
}
|
|
||||||
&Ir::Thunk(id) => {
|
|
||||||
let (layer, local) = self.resolve_thunk(id);
|
let (layer, local) = self.resolve_thunk(id);
|
||||||
InlineOperand::Local { layer, local }
|
InlineOperand::Local { layer, local }
|
||||||
}
|
}
|
||||||
&Ir::Arg { layer } => InlineOperand::Local {
|
Arg { layer } => InlineOperand::Local {
|
||||||
layer: layer.try_into().expect("scope too deep!"),
|
layer: layer.try_into().expect("scope too deep!"),
|
||||||
local: 0,
|
local: 0,
|
||||||
},
|
},
|
||||||
&Ir::Builtin(id) => {
|
|
||||||
let arity = BUILTINS[id as usize].1;
|
|
||||||
InlineOperand::Const(Const::PrimOp { id, arity })
|
|
||||||
}
|
|
||||||
Ir::Builtins => InlineOperand::Builtins,
|
|
||||||
_ => panic!("cannot classify IR node as inline operand"),
|
_ => panic!("cannot classify IR node as inline operand"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_inline_operand(&mut self, operand: InlineOperand) {
|
fn emit_maybe_thunk(&mut self, val: MaybeThunk) {
|
||||||
|
let operand = self.inline_maybe_thunk(val);
|
||||||
match operand {
|
match operand {
|
||||||
InlineOperand::Const(val) => {
|
InlineOperand::Const(val) => {
|
||||||
let idx = self.ctx.add_constant(val);
|
let idx = self.ctx.add_constant(val);
|
||||||
@@ -318,30 +314,15 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
self.count_with_thunks(*lhs) + self.count_with_thunks(*rhs)
|
self.count_with_thunks(*lhs) + self.count_with_thunks(*rhs)
|
||||||
}
|
}
|
||||||
Ir::UnOp { rhs, .. } => self.count_with_thunks(*rhs),
|
Ir::UnOp { rhs, .. } => self.count_with_thunks(*rhs),
|
||||||
Ir::Call { func, arg, .. } => {
|
Ir::Call { func, .. } => self.count_with_thunks(*func),
|
||||||
self.count_with_thunks(*func) + self.count_with_thunks(*arg)
|
|
||||||
}
|
|
||||||
Ir::Assert {
|
Ir::Assert {
|
||||||
assertion, expr, ..
|
assertion, expr, ..
|
||||||
} => self.count_with_thunks(*assertion) + self.count_with_thunks(*expr),
|
} => self.count_with_thunks(*assertion) + self.count_with_thunks(*expr),
|
||||||
Ir::Select { expr, default, .. } => {
|
Ir::Select { expr, .. } => self.count_with_thunks(*expr),
|
||||||
self.count_with_thunks(*expr) + default.map_or(0, |d| self.count_with_thunks(d))
|
|
||||||
}
|
|
||||||
Ir::HasAttr { lhs, .. } => self.count_with_thunks(*lhs),
|
Ir::HasAttr { lhs, .. } => self.count_with_thunks(*lhs),
|
||||||
Ir::ConcatStrings { parts, .. } => {
|
Ir::ConcatStrings { parts, .. } => {
|
||||||
parts.iter().map(|p| self.count_with_thunks(*p)).sum()
|
parts.iter().map(|p| self.count_with_thunks(*p)).sum()
|
||||||
}
|
}
|
||||||
Ir::Path(p) => self.count_with_thunks(*p),
|
|
||||||
Ir::List { items } => items.iter().map(|item| self.count_with_thunks(*item)).sum(),
|
|
||||||
Ir::AttrSet { stcs, dyns } => {
|
|
||||||
stcs.iter()
|
|
||||||
.map(|(_, &(val, _))| self.count_with_thunks(val))
|
|
||||||
.sum::<usize>()
|
|
||||||
+ dyns
|
|
||||||
.iter()
|
|
||||||
.map(|&(k, v, _)| self.count_with_thunks(k) + self.count_with_thunks(v))
|
|
||||||
.sum::<usize>()
|
|
||||||
}
|
|
||||||
_ => 0,
|
_ => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -390,9 +371,8 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
self.collect_with_thunks_recursive(*rhs, out);
|
self.collect_with_thunks_recursive(*rhs, out);
|
||||||
}
|
}
|
||||||
Ir::UnOp { rhs, .. } => self.collect_with_thunks_recursive(*rhs, out),
|
Ir::UnOp { rhs, .. } => self.collect_with_thunks_recursive(*rhs, out),
|
||||||
Ir::Call { func, arg, .. } => {
|
Ir::Call { func, .. } => {
|
||||||
self.collect_with_thunks_recursive(*func, out);
|
self.collect_with_thunks_recursive(*func, out);
|
||||||
self.collect_with_thunks_recursive(*arg, out);
|
|
||||||
}
|
}
|
||||||
Ir::Assert {
|
Ir::Assert {
|
||||||
assertion, expr, ..
|
assertion, expr, ..
|
||||||
@@ -400,11 +380,8 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
self.collect_with_thunks_recursive(*assertion, out);
|
self.collect_with_thunks_recursive(*assertion, out);
|
||||||
self.collect_with_thunks_recursive(*expr, out);
|
self.collect_with_thunks_recursive(*expr, out);
|
||||||
}
|
}
|
||||||
Ir::Select { expr, default, .. } => {
|
Ir::Select { expr, .. } => {
|
||||||
self.collect_with_thunks_recursive(*expr, out);
|
self.collect_with_thunks_recursive(*expr, out);
|
||||||
if let Some(d) = default {
|
|
||||||
self.collect_with_thunks_recursive(*d, out);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ir::HasAttr { lhs, .. } => self.collect_with_thunks_recursive(*lhs, out),
|
Ir::HasAttr { lhs, .. } => self.collect_with_thunks_recursive(*lhs, out),
|
||||||
Ir::ConcatStrings { parts, .. } => {
|
Ir::ConcatStrings { parts, .. } => {
|
||||||
@@ -412,22 +389,7 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
self.collect_with_thunks_recursive(*p, out);
|
self.collect_with_thunks_recursive(*p, out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ir::Path(p) => self.collect_with_thunks_recursive(*p, out),
|
_ => (),
|
||||||
Ir::List { items } => {
|
|
||||||
for item in items.iter() {
|
|
||||||
self.collect_with_thunks_recursive(*item, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ir::AttrSet { stcs, dyns } => {
|
|
||||||
for (_, &(val, _)) in stcs.iter() {
|
|
||||||
self.collect_with_thunks_recursive(val, out);
|
|
||||||
}
|
|
||||||
for &(key, val, _) in dyns.iter() {
|
|
||||||
self.collect_with_thunks_recursive(key, out);
|
|
||||||
self.collect_with_thunks_recursive(val, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,10 +472,9 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
&Ir::Bool(true) => self.emit_op(Op::PushTrue),
|
&Ir::Bool(true) => self.emit_op(Op::PushTrue),
|
||||||
&Ir::Bool(false) => self.emit_op(Op::PushFalse),
|
&Ir::Bool(false) => self.emit_op(Op::PushFalse),
|
||||||
Ir::Null => self.emit_op(Op::PushNull),
|
Ir::Null => self.emit_op(Op::PushNull),
|
||||||
Ir::Str(s) => {
|
&Ir::Str(id) => {
|
||||||
let idx = self.ctx.intern_string(s.deref());
|
|
||||||
self.emit_op(Op::PushString);
|
self.emit_op(Op::PushString);
|
||||||
self.emit_str_id(idx);
|
self.emit_str_id(id);
|
||||||
}
|
}
|
||||||
&Ir::Path(p) => {
|
&Ir::Path(p) => {
|
||||||
self.emit_expr(p);
|
self.emit_expr(p);
|
||||||
@@ -570,15 +531,14 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
self.emit_op(Op::MakeList);
|
self.emit_op(Op::MakeList);
|
||||||
self.emit_u32(items.len() as u32);
|
self.emit_u32(items.len() as u32);
|
||||||
for &item in items.iter() {
|
for &item in items.iter() {
|
||||||
let operand = self.classify_value(item);
|
self.emit_maybe_thunk(item);
|
||||||
self.emit_inline_operand(operand);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Ir::Call { func, arg, .. } => {
|
&Ir::Call { func, arg, .. } => {
|
||||||
self.emit_expr(arg);
|
|
||||||
self.emit_expr(func);
|
self.emit_expr(func);
|
||||||
self.emit_op(Op::Call);
|
self.emit_op(Op::Call);
|
||||||
|
self.inline_maybe_thunk(arg);
|
||||||
}
|
}
|
||||||
&Ir::Arg { layer } => {
|
&Ir::Arg { layer } => {
|
||||||
self.emit_load(layer.try_into().expect("scope too deep!"), 0);
|
self.emit_load(layer.try_into().expect("scope too deep!"), 0);
|
||||||
@@ -614,16 +574,17 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
&Ir::ConcatStrings {
|
&Ir::ConcatStrings {
|
||||||
ref parts,
|
parts: _,
|
||||||
force_string,
|
force_string: _,
|
||||||
} => {
|
} => {
|
||||||
self.emit_op(Op::ConcatStrings);
|
todo!("redesign ConcatStrings");
|
||||||
self.emit_u16(parts.len() as u16);
|
// self.emit_op(Op::ConcatStrings);
|
||||||
self.emit_u8(if force_string { 1 } else { 0 });
|
// self.emit_u16(parts.len() as u16);
|
||||||
for &part in parts.iter() {
|
// self.emit_u8(if force_string { 1 } else { 0 });
|
||||||
let operand = self.classify_value(part);
|
// for &part in parts.iter() {
|
||||||
self.emit_inline_operand(operand);
|
// let operand = self.inline_maybe_thunk(part);
|
||||||
}
|
// self.emit_inline_operand(operand);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
&Ir::HasAttr { lhs, ref rhs } => {
|
&Ir::HasAttr { lhs, ref rhs } => {
|
||||||
self.emit_has_attr(lhs, rhs);
|
self.emit_has_attr(lhs, rhs);
|
||||||
@@ -815,8 +776,8 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
|
|
||||||
fn emit_attrset(
|
fn emit_attrset(
|
||||||
&mut self,
|
&mut self,
|
||||||
stcs: &fix_ir::HashMap<'_, StringId, (RawIrRef<'_>, TextRange)>,
|
stcs: &fix_ir::HashMap<'_, StringId, (MaybeThunk, TextRange)>,
|
||||||
dyns: &[(RawIrRef<'_>, RawIrRef<'_>, TextRange)],
|
dyns: &[(RawIrRef<'_>, MaybeThunk, TextRange)],
|
||||||
) {
|
) {
|
||||||
if stcs.is_empty() && dyns.is_empty() {
|
if stcs.is_empty() && dyns.is_empty() {
|
||||||
self.emit_op(Op::MakeEmptyAttrs);
|
self.emit_op(Op::MakeEmptyAttrs);
|
||||||
@@ -830,19 +791,18 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
for (&sym, &(val, span)) in stcs.iter() {
|
for (&sym, &(val, span)) in stcs.iter() {
|
||||||
self.emit_u8(AttrKeyType::Static as u8);
|
self.emit_u8(AttrKeyType::Static as u8);
|
||||||
self.emit_str_id(sym);
|
self.emit_str_id(sym);
|
||||||
let val_operand = self.classify_value(val);
|
self.emit_maybe_thunk(val);
|
||||||
self.emit_inline_operand(val_operand);
|
|
||||||
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);
|
todo!("redesign dynamic attr key");
|
||||||
let key_operand = self.classify_value(key);
|
// self.emit_u8(AttrKeyType::Dynamic as u8);
|
||||||
self.emit_inline_operand(key_operand);
|
// self.emit_maybe_thunk(key);
|
||||||
let val_operand = self.classify_value(val);
|
// let val_operand = self.inline_maybe_thunk(val);
|
||||||
self.emit_inline_operand(val_operand);
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -908,12 +868,12 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
|
|
||||||
fn emit_with(
|
fn emit_with(
|
||||||
&mut self,
|
&mut self,
|
||||||
namespace: RawIrRef<'_>,
|
namespace: MaybeThunk,
|
||||||
body: RawIrRef<'_>,
|
body: RawIrRef<'_>,
|
||||||
thunks: &[(ThunkId, RawIrRef<'_>)],
|
thunks: &[(ThunkId, RawIrRef<'_>)],
|
||||||
) {
|
) {
|
||||||
self.emit_expr(namespace);
|
|
||||||
self.emit_op(Op::PushWith);
|
self.emit_op(Op::PushWith);
|
||||||
|
self.emit_maybe_thunk(namespace);
|
||||||
self.emit_scope_thunks(thunks);
|
self.emit_scope_thunks(thunks);
|
||||||
self.emit_expr(body);
|
self.emit_expr(body);
|
||||||
self.emit_op(Op::PopWith);
|
self.emit_op(Op::PopWith);
|
||||||
|
|||||||
+83
-87
@@ -1,4 +1,3 @@
|
|||||||
use bumpalo::boxed::Box;
|
|
||||||
use bumpalo::collections::{CollectIn, Vec};
|
use bumpalo::collections::{CollectIn, Vec};
|
||||||
use fix_builtins::BuiltinId;
|
use fix_builtins::BuiltinId;
|
||||||
use fix_common::Symbol;
|
use fix_common::Symbol;
|
||||||
@@ -6,7 +5,7 @@ use fix_error::{Error, Result, Source};
|
|||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use hashbrown::hash_map::Entry;
|
use hashbrown::hash_map::Entry;
|
||||||
use rnix::TextRange;
|
use rnix::TextRange;
|
||||||
use rnix::ast::{self, Expr, HasEntry};
|
use rnix::ast::{self, AstToken, Expr, HasEntry};
|
||||||
use rowan::ast::AstNode;
|
use rowan::ast::AstNode;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -39,20 +38,13 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>, T, E: std::fmt::Display>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait BoxIn: Sized {
|
|
||||||
fn box_in(self, bump: &bumpalo::Bump) -> Box<'_, Self> {
|
|
||||||
Box::new_in(self, bump)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Sized> BoxIn for T {}
|
|
||||||
|
|
||||||
pub trait DowngradeContext<'id: 'ir, 'ir> {
|
pub trait DowngradeContext<'id: 'ir, 'ir> {
|
||||||
fn new_expr(&self, expr: Ir<'ir, IrRef<'id, 'ir>>) -> IrRef<'id, 'ir>;
|
fn new_expr(&self, expr: Ir<'ir, IrRef<'id, 'ir>>) -> IrRef<'id, 'ir>;
|
||||||
fn maybe_thunk(&mut self, ir: IrRef<'id, 'ir>) -> IrRef<'id, 'ir>;
|
fn maybe_thunk(&mut self, ir: IrRef<'id, 'ir>) -> MaybeThunk;
|
||||||
|
|
||||||
fn new_sym(&mut self, sym: String) -> StringId;
|
fn intern_string(&mut self, sym: impl AsRef<str>) -> StringId;
|
||||||
fn get_sym(&self, id: StringId) -> Symbol<'_>;
|
fn resolve_sym(&self, id: StringId) -> Symbol<'_>;
|
||||||
fn lookup(&self, sym: StringId, span: TextRange) -> Result<IrRef<'id, 'ir>>;
|
fn lookup(&self, sym: StringId, span: TextRange) -> Result<MaybeThunk>;
|
||||||
|
|
||||||
fn get_current_source(&self) -> Source;
|
fn get_current_source(&self) -> Source;
|
||||||
|
|
||||||
@@ -165,14 +157,15 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo
|
|||||||
let path = {
|
let path = {
|
||||||
let temp = self.content().require(ctx, span)?;
|
let temp = self.content().require(ctx, span)?;
|
||||||
let text = temp.text();
|
let text = temp.text();
|
||||||
ctx.new_expr(Ir::Str(
|
let id = ctx.intern_string(&text[1..text.len() - 1]);
|
||||||
text[1..text.len() - 1].to_string().box_in(ctx.bump()),
|
let expr = ctx.new_expr(Ir::Str(id));
|
||||||
))
|
ctx.maybe_thunk(expr)
|
||||||
};
|
};
|
||||||
// HACK: disgusting eww
|
// HACK: disgusting eww
|
||||||
let find_file = ctx.new_expr(Ir::Builtin(BuiltinId::FindFile));
|
let find_file = ctx.new_expr(Ir::Builtin(BuiltinId::FindFile));
|
||||||
let sym = ctx.new_sym("nixPath".into());
|
let sym = ctx.intern_string("nixPath");
|
||||||
let nix_path = ctx.new_expr(Ir::BuiltinConst(sym));
|
let nix_path = ctx.new_expr(Ir::BuiltinConst(sym));
|
||||||
|
let nix_path = ctx.maybe_thunk(nix_path);
|
||||||
let call = ctx.new_expr(Ir::Call {
|
let call = ctx.new_expr(Ir::Call {
|
||||||
func: find_file,
|
func: find_file,
|
||||||
arg: nix_path,
|
arg: nix_path,
|
||||||
@@ -194,14 +187,14 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo
|
|||||||
|
|
||||||
let bump = ctx.bump();
|
let bump = ctx.bump();
|
||||||
let mut parts = normalized.into_iter().map(|part| match part {
|
let mut parts = normalized.into_iter().map(|part| match part {
|
||||||
ast::InterpolPart::Literal(lit) => Ok(ctx.new_expr(Ir::Str(lit.box_in(bump)))),
|
ast::InterpolPart::Literal(lit) => {
|
||||||
ast::InterpolPart::Interpolation(interpol) => {
|
let id = ctx.intern_string(lit);
|
||||||
let inner = interpol
|
Ok(ctx.new_expr(Ir::Str(id)))
|
||||||
|
}
|
||||||
|
ast::InterpolPart::Interpolation(interpol) => interpol
|
||||||
.expr()
|
.expr()
|
||||||
.require(ctx, interpol.syntax().text_range())?
|
.require(ctx, interpol.syntax().text_range())?
|
||||||
.downgrade(ctx)?;
|
.downgrade(ctx),
|
||||||
Ok(ctx.maybe_thunk(inner))
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(if is_single_literal {
|
Ok(if is_single_literal {
|
||||||
@@ -219,11 +212,15 @@ 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::Literal {
|
impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> for ast::Literal {
|
||||||
fn downgrade(self, ctx: &mut Ctx) -> Result<IrRef<'id, 'ir>> {
|
fn downgrade(self, ctx: &mut Ctx) -> Result<IrRef<'id, 'ir>> {
|
||||||
let span = self.syntax().text_range();
|
let span = self.syntax().text_range();
|
||||||
Ok(ctx.new_expr(match self.kind() {
|
let expr = match self.kind() {
|
||||||
ast::LiteralKind::Integer(int) => Ir::Int(int.value().require(ctx, span)?),
|
ast::LiteralKind::Integer(int) => Ir::Int(int.value().require(ctx, span)?),
|
||||||
ast::LiteralKind::Float(float) => Ir::Float(float.value().require(ctx, span)?),
|
ast::LiteralKind::Float(float) => Ir::Float(float.value().require(ctx, span)?),
|
||||||
ast::LiteralKind::Uri(uri) => Ir::Str(uri.to_string().box_in(ctx.bump())),
|
ast::LiteralKind::Uri(uri) => {
|
||||||
}))
|
let id = ctx.intern_string(uri.syntax().text());
|
||||||
|
Ir::Str(id)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(ctx.new_expr(expr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,8 +228,8 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo
|
|||||||
fn downgrade(self, ctx: &mut Ctx) -> Result<IrRef<'id, 'ir>> {
|
fn downgrade(self, ctx: &mut Ctx) -> Result<IrRef<'id, 'ir>> {
|
||||||
let span = self.syntax().text_range();
|
let span = self.syntax().text_range();
|
||||||
let text = self.ident_token().require(ctx, span)?.to_string();
|
let text = self.ident_token().require(ctx, span)?.to_string();
|
||||||
let sym = ctx.new_sym(text);
|
let sym = ctx.intern_string(text);
|
||||||
ctx.lookup(sym, span)
|
ctx.lookup(sym, span).map(|thunk| thunk.to_ir(ctx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,12 +296,10 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo
|
|||||||
let span = self.syntax().text_range();
|
let span = self.syntax().text_range();
|
||||||
let expr = self.expr().require(ctx, span)?.downgrade(ctx)?;
|
let expr = self.expr().require(ctx, span)?.downgrade(ctx)?;
|
||||||
let attrpath = downgrade_attrpath(self.attrpath().require(ctx, span)?, ctx)?;
|
let attrpath = downgrade_attrpath(self.attrpath().require(ctx, span)?, ctx)?;
|
||||||
let default = if let Some(default) = self.default_expr() {
|
let default = self
|
||||||
let default_expr = default.downgrade(ctx)?;
|
.default_expr()
|
||||||
Some(ctx.maybe_thunk(default_expr))
|
.map(|expr| expr.downgrade(ctx))
|
||||||
} else {
|
.transpose()?;
|
||||||
None
|
|
||||||
};
|
|
||||||
let span = self.syntax().text_range();
|
let span = self.syntax().text_range();
|
||||||
Ok(ctx.new_expr(Ir::Select {
|
Ok(ctx.new_expr(Ir::Select {
|
||||||
expr,
|
expr,
|
||||||
@@ -331,7 +326,7 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo
|
|||||||
Ok(ctx.new_expr(Ir::AttrSet { stcs, dyns }))
|
Ok(ctx.new_expr(Ir::AttrSet { stcs, dyns }))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let body_sym = ctx.new_sym("body".to_string());
|
let body_sym = ctx.intern_string("body");
|
||||||
Ok(ctx.new_expr(Ir::Select {
|
Ok(ctx.new_expr(Ir::Select {
|
||||||
expr: attrset_expr,
|
expr: attrset_expr,
|
||||||
attrpath: Vec::from_iter_in(
|
attrpath: Vec::from_iter_in(
|
||||||
@@ -390,7 +385,7 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo
|
|||||||
|
|
||||||
match raw_param {
|
match raw_param {
|
||||||
ast::Param::IdentParam(id) => {
|
ast::Param::IdentParam(id) => {
|
||||||
let param_sym = ctx.new_sym(id.to_string());
|
let param_sym = ctx.intern_string(id.to_string());
|
||||||
param = None;
|
param = None;
|
||||||
|
|
||||||
body = ctx.with_param_scope(param_sym, |ctx| body_ast.downgrade(ctx))?;
|
body = ctx.with_param_scope(param_sym, |ctx| body_ast.downgrade(ctx))?;
|
||||||
@@ -400,7 +395,7 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo
|
|||||||
.pat_bind()
|
.pat_bind()
|
||||||
.map(|alias| {
|
.map(|alias| {
|
||||||
let ident = alias.ident().require(ctx, alias.syntax().text_range())?;
|
let ident = alias.ident().require(ctx, alias.syntax().text_range())?;
|
||||||
Ok::<_, std::boxed::Box<Error>>(ctx.new_sym(ident.to_string()))
|
Ok::<_, std::boxed::Box<Error>>(ctx.intern_string(ident.to_string()))
|
||||||
})
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
@@ -484,7 +479,7 @@ impl<'id: 'ir, 'ir> PendingAttrSet<'ir> {
|
|||||||
|
|
||||||
match first {
|
match first {
|
||||||
ast::Attr::Ident(ident) => {
|
ast::Attr::Ident(ident) => {
|
||||||
let sym = ctx.new_sym(ident.to_string());
|
let sym = ctx.intern_string(ident.to_string());
|
||||||
self.insert_static(sym, span, rest, value, ctx)
|
self.insert_static(sym, span, rest, value, ctx)
|
||||||
}
|
}
|
||||||
ast::Attr::Str(string) => {
|
ast::Attr::Str(string) => {
|
||||||
@@ -493,7 +488,7 @@ impl<'id: 'ir, 'ir> PendingAttrSet<'ir> {
|
|||||||
&& let ast::InterpolPart::Literal(lit) =
|
&& let ast::InterpolPart::Literal(lit) =
|
||||||
parts.into_iter().next().expect("len checked")
|
parts.into_iter().next().expect("len checked")
|
||||||
{
|
{
|
||||||
let sym = ctx.new_sym(lit);
|
let sym = ctx.intern_string(lit);
|
||||||
return self.insert_static(sym, span, rest, value, ctx);
|
return self.insert_static(sym, span, rest, value, ctx);
|
||||||
}
|
}
|
||||||
self.insert_dynamic(first.clone(), span, rest, value, ctx)
|
self.insert_dynamic(first.clone(), span, rest, value, ctx)
|
||||||
@@ -736,14 +731,14 @@ impl<'id: 'ir, 'ir> PendingAttrSet<'ir> {
|
|||||||
for attr in inherit.attrs() {
|
for attr in inherit.attrs() {
|
||||||
let span = attr.syntax().text_range();
|
let span = attr.syntax().text_range();
|
||||||
let sym = match &attr {
|
let sym = match &attr {
|
||||||
ast::Attr::Ident(ident) => ctx.new_sym(ident.to_string()),
|
ast::Attr::Ident(ident) => ctx.intern_string(ident.to_string()),
|
||||||
ast::Attr::Str(s) => {
|
ast::Attr::Str(s) => {
|
||||||
let parts = s.normalized_parts();
|
let parts = s.normalized_parts();
|
||||||
if parts.len() == 1
|
if parts.len() == 1
|
||||||
&& let ast::InterpolPart::Literal(lit) =
|
&& let ast::InterpolPart::Literal(lit) =
|
||||||
parts.into_iter().next().expect("len checked")
|
parts.into_iter().next().expect("len checked")
|
||||||
{
|
{
|
||||||
ctx.new_sym(lit)
|
ctx.intern_string(lit)
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::downgrade_error(
|
return Err(Error::downgrade_error(
|
||||||
"dynamic attributes not allowed in inherit".to_string(),
|
"dynamic attributes not allowed in inherit".to_string(),
|
||||||
@@ -763,7 +758,7 @@ impl<'id: 'ir, 'ir> PendingAttrSet<'ir> {
|
|||||||
|
|
||||||
if self.stcs.contains_key(&sym) {
|
if self.stcs.contains_key(&sym) {
|
||||||
return Err(Error::downgrade_error(
|
return Err(Error::downgrade_error(
|
||||||
format!("attribute '{}' already defined", ctx.get_sym(sym)),
|
format!("attribute '{}' already defined", ctx.resolve_sym(sym)),
|
||||||
ctx.get_current_source(),
|
ctx.get_current_source(),
|
||||||
span,
|
span,
|
||||||
));
|
));
|
||||||
@@ -840,8 +835,8 @@ fn make_attrpath_value_entry<'ir>(path: Vec<'ir, ast::Attr>, value: ast::Expr) -
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct FinalizedAttrSet<'id, 'ir> {
|
struct FinalizedAttrSet<'id, 'ir> {
|
||||||
stcs: HashMap<'ir, StringId, (IrRef<'id, 'ir>, TextRange)>,
|
stcs: HashMap<'ir, StringId, (MaybeThunk, TextRange)>,
|
||||||
dyns: Vec<'ir, (IrRef<'id, 'ir>, IrRef<'id, 'ir>, TextRange)>,
|
dyns: Vec<'ir, (IrRef<'id, 'ir>, MaybeThunk, TextRange)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn downgrade_attrs<'id, 'ir>(
|
fn downgrade_attrs<'id, 'ir>(
|
||||||
@@ -861,17 +856,17 @@ fn downgrade_attr<'id, 'ir>(
|
|||||||
use ast::InterpolPart::*;
|
use ast::InterpolPart::*;
|
||||||
match attr {
|
match attr {
|
||||||
Ident(ident) => Ok(Attr::Str(
|
Ident(ident) => Ok(Attr::Str(
|
||||||
ctx.new_sym(ident.to_string()),
|
ctx.intern_string(ident.to_string()),
|
||||||
ident.syntax().text_range(),
|
ident.syntax().text_range(),
|
||||||
)),
|
)),
|
||||||
Str(string) => {
|
Str(string) => {
|
||||||
let parts = string.normalized_parts();
|
let parts = string.normalized_parts();
|
||||||
let span = string.syntax().text_range();
|
let span = string.syntax().text_range();
|
||||||
if parts.is_empty() {
|
if parts.is_empty() {
|
||||||
Ok(Attr::Str(ctx.new_sym("".to_string()), span))
|
Ok(Attr::Str(ctx.intern_string(""), span))
|
||||||
} else if parts.len() == 1 {
|
} else if parts.len() == 1 {
|
||||||
match parts.into_iter().next().expect("len checked") {
|
match parts.into_iter().next().expect("len checked") {
|
||||||
Literal(ident) => Ok(Attr::Str(ctx.new_sym(ident), span)),
|
Literal(ident) => Ok(Attr::Str(ctx.intern_string(ident), span)),
|
||||||
Interpolation(interpol) => Ok(Attr::Dynamic(
|
Interpolation(interpol) => Ok(Attr::Dynamic(
|
||||||
interpol
|
interpol
|
||||||
.expr()
|
.expr()
|
||||||
@@ -885,7 +880,10 @@ fn downgrade_attr<'id, 'ir>(
|
|||||||
let parts = parts
|
let parts = parts
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|part| match part {
|
.map(|part| match part {
|
||||||
Literal(lit) => Ok(ctx.new_expr(Ir::Str(lit.box_in(bump)))),
|
Literal(lit) => {
|
||||||
|
let id = ctx.intern_string(lit);
|
||||||
|
Ok(ctx.new_expr(Ir::Str(id)))
|
||||||
|
}
|
||||||
Interpolation(interpol) => interpol
|
Interpolation(interpol) => interpol
|
||||||
.expr()
|
.expr()
|
||||||
.require(ctx, interpol.syntax().text_range())?
|
.require(ctx, interpol.syntax().text_range())?
|
||||||
@@ -950,13 +948,13 @@ where
|
|||||||
for entry in pat_entries {
|
for entry in pat_entries {
|
||||||
let ident = entry.ident().require(ctx, entry.syntax().text_range())?;
|
let ident = entry.ident().require(ctx, entry.syntax().text_range())?;
|
||||||
let sym_span = ident.syntax().text_range();
|
let sym_span = ident.syntax().text_range();
|
||||||
let sym = ctx.new_sym(ident.syntax().text().to_string());
|
let sym = ctx.intern_string(ident.syntax().text().to_string());
|
||||||
let default = entry.default();
|
let default = entry.default();
|
||||||
let span = entry.syntax().text_range();
|
let span = entry.syntax().text_range();
|
||||||
|
|
||||||
if !seen_params.insert(sym) {
|
if !seen_params.insert(sym) {
|
||||||
return Err(Error::downgrade_error(
|
return Err(Error::downgrade_error(
|
||||||
format!("duplicate parameter '{}'", ctx.get_sym(sym)),
|
format!("duplicate parameter '{}'", ctx.resolve_sym(sym)),
|
||||||
ctx.get_current_source(),
|
ctx.get_current_source(),
|
||||||
span,
|
span,
|
||||||
));
|
));
|
||||||
@@ -1001,12 +999,13 @@ where
|
|||||||
default,
|
default,
|
||||||
span,
|
span,
|
||||||
} = param;
|
} = param;
|
||||||
let default = if let Some(default) = default {
|
let default = default.map(|default| default.downgrade(ctx)).transpose()?;
|
||||||
let default = default.clone().downgrade(ctx)?;
|
// let default = if let Some(default) = default {
|
||||||
Some(ctx.maybe_thunk(default))
|
// let default = default.clone().downgrade(ctx)?;
|
||||||
} else {
|
// Some(ctx.maybe_thunk(default))
|
||||||
None
|
// } else {
|
||||||
};
|
// None
|
||||||
|
// };
|
||||||
|
|
||||||
Ok(ctx.new_expr(Ir::Select {
|
Ok(ctx.new_expr(Ir::Select {
|
||||||
expr: arg,
|
expr: arg,
|
||||||
@@ -1075,7 +1074,7 @@ where
|
|||||||
F: FnOnce(
|
F: FnOnce(
|
||||||
&mut Ctx,
|
&mut Ctx,
|
||||||
&[StringId],
|
&[StringId],
|
||||||
&[(IrRef<'id, 'ir>, IrRef<'id, 'ir>, TextRange)],
|
&[(IrRef<'id, 'ir>, MaybeThunk, TextRange)],
|
||||||
) -> Result<IrRef<'id, 'ir>>,
|
) -> Result<IrRef<'id, 'ir>>,
|
||||||
{
|
{
|
||||||
let mut pending = PendingAttrSet::new_in(ctx.bump());
|
let mut pending = PendingAttrSet::new_in(ctx.bump());
|
||||||
@@ -1088,18 +1087,21 @@ where
|
|||||||
|
|
||||||
ctx.with_let_scope(&keys, |ctx| {
|
ctx.with_let_scope(&keys, |ctx| {
|
||||||
let finalized = finalize_pending_set::<_, ALLOW_DYN>(pending, &inherit_lookups, ctx)?;
|
let finalized = finalize_pending_set::<_, ALLOW_DYN>(pending, &inherit_lookups, ctx)?;
|
||||||
let vals = keys
|
let vals = {
|
||||||
.iter()
|
let mut temp = Vec::with_capacity_in(keys.len(), ctx.bump());
|
||||||
.map(|sym| finalized.stcs.get(sym).expect("WTF").0)
|
for sym in &keys {
|
||||||
.collect_in(ctx.bump());
|
temp.push(finalized.stcs.get(sym).expect("WTF").0.to_ir(ctx));
|
||||||
|
}
|
||||||
|
temp
|
||||||
|
};
|
||||||
body_fn(ctx, &keys, &finalized.dyns).map(|body| (vals, body))
|
body_fn(ctx, &keys, &finalized.dyns).map(|body| (vals, body))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_inherit_lookups<'id, 'ir, Ctx: DowngradeContext<'id, 'ir>>(
|
fn collect_inherit_lookups<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>>(
|
||||||
entries: &[ast::Entry],
|
entries: &[ast::Entry],
|
||||||
ctx: &mut Ctx,
|
ctx: &mut Ctx,
|
||||||
) -> Result<HashMap<'ir, StringId, (IrRef<'id, 'ir>, TextRange)>> {
|
) -> Result<HashMap<'ir, StringId, (MaybeThunk, TextRange)>> {
|
||||||
let mut inherit_lookups = HashMap::new_in(ctx.bump());
|
let mut inherit_lookups = HashMap::new_in(ctx.bump());
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
if let ast::Entry::Inherit(inherit) = entry
|
if let ast::Entry::Inherit(inherit) = entry
|
||||||
@@ -1108,7 +1110,7 @@ fn collect_inherit_lookups<'id, 'ir, Ctx: DowngradeContext<'id, 'ir>>(
|
|||||||
for attr in inherit.attrs() {
|
for attr in inherit.attrs() {
|
||||||
if let ast::Attr::Ident(ident) = attr {
|
if let ast::Attr::Ident(ident) = attr {
|
||||||
let attr_span = ident.syntax().text_range();
|
let attr_span = ident.syntax().text_range();
|
||||||
let sym = ctx.new_sym(ident.to_string());
|
let sym = ctx.intern_string(ident.to_string());
|
||||||
let expr = ctx.lookup(sym, attr_span)?;
|
let expr = ctx.lookup(sym, attr_span)?;
|
||||||
inherit_lookups.insert(sym, (expr, attr_span));
|
inherit_lookups.insert(sym, (expr, attr_span));
|
||||||
}
|
}
|
||||||
@@ -1127,7 +1129,7 @@ fn collect_binding_syms<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>, const AL
|
|||||||
for (sym, (_, span)) in &pending.stcs {
|
for (sym, (_, span)) in &pending.stcs {
|
||||||
if !binding_syms.insert(*sym) {
|
if !binding_syms.insert(*sym) {
|
||||||
return Err(Error::downgrade_error(
|
return Err(Error::downgrade_error(
|
||||||
format!("attribute '{}' already defined", ctx.get_sym(*sym)),
|
format!("attribute '{}' already defined", ctx.resolve_sym(*sym)),
|
||||||
ctx.get_current_source(),
|
ctx.get_current_source(),
|
||||||
*span,
|
*span,
|
||||||
));
|
));
|
||||||
@@ -1139,15 +1141,15 @@ fn collect_binding_syms<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>, const AL
|
|||||||
|
|
||||||
fn finalize_pending_set<'id, 'ir, Ctx: DowngradeContext<'id, 'ir>, const ALLOW_DYN: bool>(
|
fn finalize_pending_set<'id, 'ir, Ctx: DowngradeContext<'id, 'ir>, const ALLOW_DYN: bool>(
|
||||||
pending: PendingAttrSet,
|
pending: PendingAttrSet,
|
||||||
inherit_lookups: &HashMap<StringId, (IrRef<'id, 'ir>, TextRange)>,
|
inherit_lookups: &HashMap<StringId, (MaybeThunk, TextRange)>,
|
||||||
ctx: &mut Ctx,
|
ctx: &mut Ctx,
|
||||||
) -> Result<FinalizedAttrSet<'id, 'ir>> {
|
) -> Result<FinalizedAttrSet<'id, 'ir>> {
|
||||||
let mut stcs = HashMap::new_in(ctx.bump());
|
let mut stcs = HashMap::new_in(ctx.bump());
|
||||||
let mut dyns = Vec::new_in(ctx.bump());
|
let mut dyns = Vec::new_in(ctx.bump());
|
||||||
|
|
||||||
for (sym, (value, value_span)) in pending.stcs {
|
for (sym, (value, value_span)) in pending.stcs {
|
||||||
let expr_id = finalize_pending_value::<_, ALLOW_DYN>(value, inherit_lookups, ctx)?;
|
let expr = finalize_pending_value::<_, ALLOW_DYN>(value, inherit_lookups, ctx)?;
|
||||||
stcs.insert(sym, (expr_id, value_span));
|
stcs.insert(sym, (ctx.maybe_thunk(expr), value_span));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ALLOW_DYN {
|
if ALLOW_DYN {
|
||||||
@@ -1155,12 +1157,10 @@ fn finalize_pending_set<'id, 'ir, Ctx: DowngradeContext<'id, 'ir>, const ALLOW_D
|
|||||||
let key_id = downgrade_attr(attr, ctx)?;
|
let key_id = downgrade_attr(attr, ctx)?;
|
||||||
let key_expr = match key_id {
|
let key_expr = match key_id {
|
||||||
Attr::Dynamic(id, _) => id,
|
Attr::Dynamic(id, _) => id,
|
||||||
Attr::Str(sym, _attr_span) => {
|
Attr::Str(sym, _attr_span) => ctx.new_expr(Ir::Str(sym)),
|
||||||
ctx.new_expr(Ir::Str(ctx.get_sym(sym).to_string().box_in(ctx.bump())))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let value_id = finalize_pending_value::<_, ALLOW_DYN>(value, inherit_lookups, ctx)?;
|
let value = finalize_pending_value::<_, ALLOW_DYN>(value, inherit_lookups, ctx)?;
|
||||||
dyns.push((key_expr, value_id, value_span));
|
dyns.push((key_expr, ctx.maybe_thunk(value), value_span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1169,30 +1169,25 @@ fn finalize_pending_set<'id, 'ir, Ctx: DowngradeContext<'id, 'ir>, const ALLOW_D
|
|||||||
|
|
||||||
fn finalize_pending_value<'id, 'ir, Ctx: DowngradeContext<'id, 'ir>, const ALLOW_DYN: bool>(
|
fn finalize_pending_value<'id, 'ir, Ctx: DowngradeContext<'id, 'ir>, const ALLOW_DYN: bool>(
|
||||||
value: PendingValue,
|
value: PendingValue,
|
||||||
inherit_lookups: &HashMap<StringId, (IrRef<'id, 'ir>, TextRange)>,
|
inherit_lookups: &HashMap<StringId, (MaybeThunk, TextRange)>,
|
||||||
ctx: &mut Ctx,
|
ctx: &mut Ctx,
|
||||||
) -> Result<IrRef<'id, 'ir>> {
|
) -> Result<IrRef<'id, 'ir>> {
|
||||||
match value {
|
match value {
|
||||||
PendingValue::Expr(expr) => {
|
PendingValue::Expr(expr) => expr.downgrade(ctx),
|
||||||
let id = Downgrade::downgrade(expr, ctx)?;
|
|
||||||
Ok(ctx.maybe_thunk(id))
|
|
||||||
}
|
|
||||||
PendingValue::InheritFrom(from_expr, sym, span) => {
|
PendingValue::InheritFrom(from_expr, sym, span) => {
|
||||||
let from_id = Downgrade::downgrade(from_expr, ctx)?;
|
let from = Downgrade::downgrade(from_expr, ctx)?;
|
||||||
let select_id = ctx.new_expr(Ir::Select {
|
Ok(ctx.new_expr(Ir::Select {
|
||||||
expr: from_id,
|
expr: from,
|
||||||
attrpath: Vec::from_iter_in([Attr::Str(sym, span)], ctx.bump()),
|
attrpath: Vec::from_iter_in([Attr::Str(sym, span)], ctx.bump()),
|
||||||
default: None,
|
default: None,
|
||||||
span,
|
span,
|
||||||
});
|
}))
|
||||||
Ok(ctx.maybe_thunk(select_id))
|
|
||||||
}
|
}
|
||||||
PendingValue::InheritScope(sym, span) => {
|
PendingValue::InheritScope(sym, span) => {
|
||||||
if let Some(&(expr, _)) = inherit_lookups.get(&sym) {
|
if let Some(&(expr, _)) = inherit_lookups.get(&sym) {
|
||||||
Ok(ctx.maybe_thunk(expr))
|
Ok(expr.to_ir(ctx))
|
||||||
} else {
|
} else {
|
||||||
let lookup_id = ctx.lookup(sym, span)?;
|
ctx.lookup(sym, span).map(|val| val.to_ir(ctx))
|
||||||
Ok(ctx.maybe_thunk(lookup_id))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PendingValue::Set(set) => {
|
PendingValue::Set(set) => {
|
||||||
@@ -1221,7 +1216,8 @@ fn downgrade_path<'id, 'ir>(
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|part| match part {
|
.map(|part| match part {
|
||||||
ast::InterpolPart::Literal(lit) => {
|
ast::InterpolPart::Literal(lit) => {
|
||||||
Ok(ctx.new_expr(Ir::Str(lit.text().to_string().box_in(ctx.bump()))))
|
let id = ctx.intern_string(lit.text());
|
||||||
|
Ok(ctx.new_expr(Ir::Str(id)))
|
||||||
}
|
}
|
||||||
ast::InterpolPart::Interpolation(interpol) => interpol
|
ast::InterpolPart::Interpolation(interpol) => interpol
|
||||||
.expr()
|
.expr()
|
||||||
|
|||||||
+49
-8
@@ -2,7 +2,6 @@ use std::hash::Hash;
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use bumpalo::boxed::Box;
|
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use fix_builtins::{BUILTINS, BuiltinId};
|
use fix_builtins::{BUILTINS, BuiltinId};
|
||||||
use fix_common::StringId;
|
use fix_common::StringId;
|
||||||
@@ -11,6 +10,8 @@ use num_enum::TryFromPrimitive as _;
|
|||||||
use rnix::{TextRange, ast};
|
use rnix::{TextRange, ast};
|
||||||
use string_interner::DefaultStringInterner;
|
use string_interner::DefaultStringInterner;
|
||||||
|
|
||||||
|
use crate::downgrade::DowngradeContext;
|
||||||
|
|
||||||
pub mod downgrade;
|
pub mod downgrade;
|
||||||
|
|
||||||
pub type HashMap<'ir, K, V> = hashbrown::HashMap<K, V, hashbrown::DefaultHashBuilder, &'ir Bump>;
|
pub type HashMap<'ir, K, V> = hashbrown::HashMap<K, V, hashbrown::DefaultHashBuilder, &'ir Bump>;
|
||||||
@@ -62,6 +63,46 @@ impl<'ir> Deref for RawIrRef<'ir> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum MaybeThunk {
|
||||||
|
Int(i64),
|
||||||
|
Float(f64),
|
||||||
|
Bool(bool),
|
||||||
|
Null,
|
||||||
|
Str(StringId),
|
||||||
|
Path(StringId),
|
||||||
|
Thunk(ThunkId),
|
||||||
|
Arg { layer: usize },
|
||||||
|
Builtin(BuiltinId),
|
||||||
|
Builtins,
|
||||||
|
ReplBinding(StringId),
|
||||||
|
ScopedImportBinding(StringId),
|
||||||
|
WithLookup(StringId),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaybeThunk {
|
||||||
|
fn to_ir<'id, 'ir>(self, ctx: &mut impl DowngradeContext<'id, 'ir>) -> IrRef<'id, 'ir> {
|
||||||
|
use MaybeThunk::*;
|
||||||
|
let ir = match self {
|
||||||
|
Int(x) => Ir::Int(x),
|
||||||
|
Float(x) => Ir::Float(x),
|
||||||
|
Bool(x) => Ir::Bool(x),
|
||||||
|
Null => Ir::Null,
|
||||||
|
Str(x) => Ir::Str(x),
|
||||||
|
Path(x) => Ir::Path(ctx.new_expr(Ir::Str(x))),
|
||||||
|
Thunk(x) => Ir::Thunk(x),
|
||||||
|
Arg { layer } => Ir::Arg { layer },
|
||||||
|
Builtin(x) => Ir::Builtin(x),
|
||||||
|
Builtins => Ir::Builtins,
|
||||||
|
ReplBinding(x) => Ir::ReplBinding(x),
|
||||||
|
ScopedImportBinding(x) => Ir::ScopedImportBinding(x),
|
||||||
|
WithLookup(x) => Ir::WithLookup(x),
|
||||||
|
};
|
||||||
|
ctx.new_expr(ir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Ir<'ir, Ref> {
|
pub enum Ir<'ir, Ref> {
|
||||||
@@ -69,15 +110,15 @@ pub enum Ir<'ir, Ref> {
|
|||||||
Float(f64),
|
Float(f64),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
Null,
|
Null,
|
||||||
Str(Box<'ir, String>),
|
Str(StringId),
|
||||||
|
Path(Ref),
|
||||||
AttrSet {
|
AttrSet {
|
||||||
stcs: HashMap<'ir, StringId, (Ref, TextRange)>,
|
stcs: HashMap<'ir, StringId, (MaybeThunk, TextRange)>,
|
||||||
dyns: Vec<'ir, (Ref, Ref, TextRange)>,
|
dyns: Vec<'ir, (Ref, MaybeThunk, TextRange)>,
|
||||||
},
|
},
|
||||||
List {
|
List {
|
||||||
items: Vec<'ir, Ref>,
|
items: Vec<'ir, MaybeThunk>,
|
||||||
},
|
},
|
||||||
Path(Ref),
|
|
||||||
ConcatStrings {
|
ConcatStrings {
|
||||||
parts: Vec<'ir, Ref>,
|
parts: Vec<'ir, Ref>,
|
||||||
force_string: bool,
|
force_string: bool,
|
||||||
@@ -118,7 +159,7 @@ pub enum Ir<'ir, Ref> {
|
|||||||
},
|
},
|
||||||
|
|
||||||
With {
|
With {
|
||||||
namespace: Ref,
|
namespace: MaybeThunk,
|
||||||
body: Ref,
|
body: Ref,
|
||||||
thunks: Vec<'ir, (ThunkId, Ref)>,
|
thunks: Vec<'ir, (ThunkId, Ref)>,
|
||||||
},
|
},
|
||||||
@@ -135,7 +176,7 @@ pub enum Ir<'ir, Ref> {
|
|||||||
},
|
},
|
||||||
Call {
|
Call {
|
||||||
func: Ref,
|
func: Ref,
|
||||||
arg: Ref,
|
arg: MaybeThunk,
|
||||||
span: TextRange,
|
span: TextRange,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ impl<T: Default + Copy, const N: usize> ArrayExt<N> for [T; N] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RawStore: Sized {
|
pub(crate) trait RawStore: Sized {
|
||||||
fn to_val(self, value: &mut Value);
|
fn to_val(self, value: &mut Value);
|
||||||
fn from_val(value: &Value) -> Self;
|
fn from_val(value: &Value) -> Self;
|
||||||
}
|
}
|
||||||
|
|||||||
+568
-898
File diff suppressed because it is too large
Load Diff
@@ -1,76 +0,0 @@
|
|||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
use gc_arena::Collect;
|
|
||||||
|
|
||||||
pub(super) struct Stack<const N: usize, T> {
|
|
||||||
inner: Box<[MaybeUninit<T>; N]>,
|
|
||||||
len: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'gc, const N: usize, T: Collect<'gc> + 'gc> Collect<'gc> for Stack<N, T> {
|
|
||||||
const NEEDS_TRACE: bool = T::NEEDS_TRACE;
|
|
||||||
fn trace<U: gc_arena::collect::Trace<'gc>>(&self, cc: &mut U) {
|
|
||||||
for item in self.inner[..self.len].iter() {
|
|
||||||
unsafe {
|
|
||||||
item.assume_init_ref().trace(cc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const N: usize, T> Default for Stack<N, T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const N: usize, T> Stack<N, T> {
|
|
||||||
pub(super) fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
inner: Box::new([const { MaybeUninit::uninit() }; N]),
|
|
||||||
len: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn push(&mut self, val: T) -> Result<(), T> {
|
|
||||||
if self.len == N {
|
|
||||||
return Err(val);
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
self.inner.get_unchecked_mut(self.len).write(val);
|
|
||||||
}
|
|
||||||
self.len += 1;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn pop(&mut self) -> Option<T> {
|
|
||||||
if self.len == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let ret = unsafe {
|
|
||||||
self.inner
|
|
||||||
.get_unchecked_mut(self.len - 1)
|
|
||||||
.assume_init_read()
|
|
||||||
};
|
|
||||||
self.len -= 1;
|
|
||||||
Some(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn tos(&self) -> Option<&T> {
|
|
||||||
if self.len == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(unsafe { self.inner.get_unchecked(self.len - 1).assume_init_ref() })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn tos_mut(&mut self) -> Option<&mut T> {
|
|
||||||
if self.len == 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(unsafe { self.inner.get_unchecked_mut(self.len - 1).assume_init_mut() })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn len(&self) -> usize {
|
|
||||||
self.len
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+10
-11
@@ -22,13 +22,14 @@ mod private {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
///
|
||||||
/// 1. TAG must be unique among all implementors.
|
/// 1. TAG must be unique among all implementors.
|
||||||
/// 2. TAG must be within 1..=7
|
/// 2. TAG must be within 1..=7
|
||||||
pub(crate) unsafe trait Storable: private::Cealed {
|
pub unsafe trait Storable: private::Cealed {
|
||||||
const TAG: (bool, u8);
|
const TAG: (bool, u8);
|
||||||
}
|
}
|
||||||
pub(crate) trait InlineStorable: Storable + RawStore {}
|
pub trait InlineStorable: Storable + RawStore {}
|
||||||
pub(crate) trait GcStorable: Storable {}
|
pub trait GcStorable: Storable {}
|
||||||
|
|
||||||
macro_rules! define_value_types {
|
macro_rules! define_value_types {
|
||||||
(
|
(
|
||||||
@@ -263,11 +264,11 @@ impl<'gc> Value<'gc> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn restrict(self) -> Option<StrictValue<'gc>> {
|
pub(crate) fn restrict(self) -> Result<StrictValue<'gc>, Gc<'gc, Thunk<'gc>>> {
|
||||||
if !self.is::<Thunk<'gc>>() {
|
if let Some(thunk) = self.as_gc::<Thunk<'gc>>() {
|
||||||
Some(StrictValue(self))
|
Err(thunk)
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok(StrictValue(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,9 +385,7 @@ impl<'gc> Deref for AttrSet<'gc> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> AttrSet<'gc> {
|
impl<'gc> AttrSet<'gc> {
|
||||||
pub(crate) fn from_sorted_unchecked(
|
pub(crate) fn from_sorted_unchecked(entries: SmallVec<[(StringId, Value<'gc>); 4]>) -> Self {
|
||||||
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 { entries }
|
Self { entries }
|
||||||
}
|
}
|
||||||
@@ -464,7 +463,7 @@ pub(crate) enum ThunkState<'gc> {
|
|||||||
arg: Value<'gc>,
|
arg: Value<'gc>,
|
||||||
},
|
},
|
||||||
Blackhole,
|
Blackhole,
|
||||||
Evaluated(Value<'gc>),
|
Evaluated(StrictValue<'gc>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Collect, Debug)]
|
#[derive(Collect, Debug)]
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ miette = { version = "7.4", features = ["fancy"] }
|
|||||||
|
|
||||||
# Data Structure
|
# Data Structure
|
||||||
hashbrown = { workspace = true }
|
hashbrown = { workspace = true }
|
||||||
smallvec = { workspace = true }
|
|
||||||
string-interner = { workspace = true }
|
string-interner = { workspace = true }
|
||||||
|
|
||||||
# Memory Management
|
# Memory Management
|
||||||
|
|||||||
+53
-23
@@ -2,15 +2,16 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
use fix_codegen::disassembler::{Disassembler, DisassemblerContext};
|
||||||
use fix_codegen::{BytecodeContext, InstructionPtr};
|
use fix_codegen::{BytecodeContext, InstructionPtr};
|
||||||
use fix_common::{StringId, Symbol};
|
use fix_common::{StringId, Symbol};
|
||||||
use fix_error::{Error, Result, Source};
|
use fix_error::{Error, Result, Source};
|
||||||
use fix_ir::downgrade::{Downgrade as _, DowngradeContext};
|
use fix_ir::downgrade::{Downgrade as _, DowngradeContext};
|
||||||
use fix_ir::{Ir, IrRef, RawIrRef, ThunkId};
|
use fix_ir::{Ir, IrRef, MaybeThunk, RawIrRef, ThunkId};
|
||||||
use fix_vm::{ForceMode, StaticValue, Vm, VmContext};
|
use fix_vm::{ForceMode, StaticValue, Vm, VmContext};
|
||||||
use ghost_cell::{GhostCell, GhostToken};
|
use ghost_cell::{GhostCell, GhostToken};
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use string_interner::DefaultStringInterner;
|
use string_interner::{DefaultStringInterner, Symbol as _};
|
||||||
|
|
||||||
// mod fetcher;
|
// mod fetcher;
|
||||||
// mod nar;
|
// mod nar;
|
||||||
@@ -105,6 +106,10 @@ impl Evaluator {
|
|||||||
Ok(ip)
|
Ok(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn disassemble_colored(&self, ip: InstructionPtr) -> String {
|
||||||
|
Disassembler::new(ip, self).disassemble_colored()
|
||||||
|
}
|
||||||
|
|
||||||
fn downgrade_ctx<'a, 'bump, 'id>(
|
fn downgrade_ctx<'a, 'bump, 'id>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
bump: &'bump Bump,
|
bump: &'bump Bump,
|
||||||
@@ -289,56 +294,66 @@ impl<'ctx: 'ir, 'id, 'ir> DowngradeContext<'id, 'ir> for DowngradeCtx<'ctx, 'id,
|
|||||||
IrRef::new(self.bump.alloc(GhostCell::new(expr)))
|
IrRef::new(self.bump.alloc(GhostCell::new(expr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_thunk(&mut self, ir: IrRef<'id, 'ir>) -> IrRef<'id, 'ir> {
|
fn maybe_thunk(&mut self, ir: IrRef<'id, 'ir>) -> MaybeThunk {
|
||||||
if !should_thunk(ir, &self.token) {
|
use MaybeThunk::*;
|
||||||
return ir;
|
match *ir.borrow(&self.token) {
|
||||||
|
Ir::Builtin(x) => return Builtin(x),
|
||||||
|
Ir::Int(x) => return Int(x),
|
||||||
|
Ir::Float(x) => return Float(x),
|
||||||
|
Ir::Bool(x) => return Bool(x),
|
||||||
|
Ir::Str(x) => return Str(x),
|
||||||
|
Ir::Thunk(x) => return Thunk(x),
|
||||||
|
Ir::Arg { layer } => return Arg { layer },
|
||||||
|
Ir::Builtins => return Builtins,
|
||||||
|
Ir::Null => return Null,
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = ThunkId(*self.thunk_count);
|
let id = ThunkId(*self.thunk_count);
|
||||||
*self.thunk_count = self.thunk_count.checked_add(1).expect("thunk id overflow");
|
*self.thunk_count = self.thunk_count.checked_add(1).expect("thunk id overflow");
|
||||||
self.thunk_scopes
|
self.thunk_scopes
|
||||||
.last_mut()
|
.last_mut()
|
||||||
.expect("no active cache scope")
|
.expect("no active cache scope")
|
||||||
.add_binding(id, ir, &self.token);
|
.add_binding(id, ir, &self.token);
|
||||||
IrRef::alloc(self.bump, Ir::Thunk(id))
|
Thunk(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_sym(&mut self, sym: String) -> StringId {
|
fn intern_string(&mut self, sym: impl AsRef<str>) -> StringId {
|
||||||
StringId(self.strings.get_or_intern(sym))
|
StringId(self.strings.get_or_intern(sym))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_sym(&self, id: StringId) -> Symbol<'_> {
|
fn resolve_sym(&self, id: StringId) -> Symbol<'_> {
|
||||||
self.strings.resolve(id.0).expect("no symbol found").into()
|
self.strings.resolve(id.0).expect("no symbol found").into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup(&self, sym: StringId, span: rnix::TextRange) -> Result<IrRef<'id, 'ir>> {
|
fn lookup(&self, sym: StringId, span: rnix::TextRange) -> Result<MaybeThunk> {
|
||||||
for scope in self.scopes.iter().rev() {
|
for scope in self.scopes.iter().rev() {
|
||||||
match scope {
|
match scope {
|
||||||
&Scope::Global(global_scope) => {
|
&Scope::Global(global_scope) => {
|
||||||
|
use MaybeThunk::*;
|
||||||
if let Some(expr) = global_scope.get(&sym) {
|
if let Some(expr) = global_scope.get(&sym) {
|
||||||
let ir = match expr {
|
let val = match expr {
|
||||||
Ir::Builtins => Ir::Builtins,
|
Ir::Builtins => Builtins,
|
||||||
Ir::Builtin(s) => Ir::Builtin(*s),
|
Ir::Builtin(s) => Builtin(*s),
|
||||||
Ir::Bool(b) => Ir::Bool(*b),
|
Ir::Bool(b) => Bool(*b),
|
||||||
Ir::Null => Ir::Null,
|
Ir::Null => Null,
|
||||||
_ => unreachable!("globals should only contain leaf IR nodes"),
|
_ => unreachable!("globals should only contain leaf IR nodes"),
|
||||||
};
|
};
|
||||||
return Ok(self.new_expr(ir));
|
return Ok(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Scope::Repl(repl_bindings) => {
|
&Scope::Repl(repl_bindings) => {
|
||||||
if repl_bindings.contains(&sym) {
|
if repl_bindings.contains(&sym) {
|
||||||
return Ok(self.new_expr(Ir::ReplBinding(sym)));
|
return Ok(MaybeThunk::ReplBinding(sym));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::ScopedImport(scoped_bindings) => {
|
Scope::ScopedImport(scoped_bindings) => {
|
||||||
if scoped_bindings.contains(&sym) {
|
if scoped_bindings.contains(&sym) {
|
||||||
return Ok(self.new_expr(Ir::ScopedImportBinding(sym)));
|
return Ok(MaybeThunk::ScopedImportBinding(sym));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::Let(let_scope) => {
|
Scope::Let(let_scope) => {
|
||||||
if let Some(&expr) = let_scope.get(&sym) {
|
if let Some(&expr) = let_scope.get(&sym) {
|
||||||
return Ok(self.new_expr(Ir::Thunk(expr)));
|
return Ok(MaybeThunk::Thunk(expr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Scope::Param {
|
&Scope::Param {
|
||||||
@@ -346,19 +361,19 @@ impl<'ctx: 'ir, 'id, 'ir> DowngradeContext<'id, 'ir> for DowngradeCtx<'ctx, 'id,
|
|||||||
abs_layer,
|
abs_layer,
|
||||||
} => {
|
} => {
|
||||||
if param_sym == sym {
|
if param_sym == sym {
|
||||||
return Ok(self.new_expr(Ir::Arg {
|
return Ok(MaybeThunk::Arg {
|
||||||
layer: self.thunk_scopes.len() - abs_layer,
|
layer: self.thunk_scopes.len() - abs_layer,
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.with_scope_count > 0 {
|
if self.with_scope_count > 0 {
|
||||||
Ok(self.new_expr(Ir::WithLookup(sym)))
|
Ok(MaybeThunk::WithLookup(sym))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::downgrade_error(
|
Err(Error::downgrade_error(
|
||||||
format!("'{}' not found", self.get_sym(sym)),
|
format!("'{}' not found", self.resolve_sym(sym)),
|
||||||
self.get_current_source(),
|
self.get_current_source(),
|
||||||
span,
|
span,
|
||||||
))
|
))
|
||||||
@@ -504,6 +519,9 @@ struct OwnedIr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OwnedIr {
|
impl OwnedIr {
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// `ir` must be allocated from `bump`.
|
||||||
unsafe fn new(ir: RawIrRef<'_>, bump: Bump) -> Self {
|
unsafe fn new(ir: RawIrRef<'_>, bump: Bump) -> Self {
|
||||||
Self {
|
Self {
|
||||||
_bump: bump,
|
_bump: bump,
|
||||||
@@ -553,3 +571,15 @@ impl BytecodeContext for Evaluator {
|
|||||||
self.constants.insert(val)
|
self.constants.insert(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DisassemblerContext for Evaluator {
|
||||||
|
fn get_code(&self) -> &[u8] {
|
||||||
|
&self.bytecode
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
fn resolve_string(&self, id: u32) -> &str {
|
||||||
|
let id = string_interner::symbol::SymbolU32::try_from_usize(id as usize).unwrap();
|
||||||
|
self.strings.resolve(id).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+5
-5
@@ -40,7 +40,7 @@ struct ExprSource {
|
|||||||
file: Option<PathBuf>,
|
file: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_compile(eval: &mut Evaluator, src: ExprSource, _silent: bool) -> Result<()> {
|
fn run_compile(eval: &mut Evaluator, src: ExprSource, silent: bool) -> Result<()> {
|
||||||
let src = if let Some(expr) = src.expr {
|
let src = if let Some(expr) = src.expr {
|
||||||
Source::new_eval(expr)?
|
Source::new_eval(expr)?
|
||||||
} else if let Some(file) = src.file {
|
} else if let Some(file) = src.file {
|
||||||
@@ -49,10 +49,10 @@ fn run_compile(eval: &mut Evaluator, src: ExprSource, _silent: bool) -> Result<(
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
match eval.compile_bytecode(src) {
|
match eval.compile_bytecode(src) {
|
||||||
Ok(_ip) => {
|
Ok(ip) => {
|
||||||
// if !silent {
|
if !silent {
|
||||||
// println!("{}", eval.disassemble_colored(ip));
|
println!("{}", eval.disassemble_colored(ip));
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("{:?}", miette::Report::new(*err));
|
eprintln!("{:?}", miette::Report::new(*err));
|
||||||
|
|||||||
Generated
+9
-9
@@ -8,11 +8,11 @@
|
|||||||
"rust-analyzer-src": "rust-analyzer-src"
|
"rust-analyzer-src": "rust-analyzer-src"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1774596377,
|
"lastModified": 1775807984,
|
||||||
"narHash": "sha256-DiSLMxyTwIUAlhOe34r6kKNQRv6PTF+vf0MG45mAyn4=",
|
"narHash": "sha256-Redoe3D9zGN5I9QPHWL9vfMVQBehY1fKsMiRXQ83X3w=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "fenix",
|
"repo": "fenix",
|
||||||
"rev": "a88a1c8cf2f094da6347fcec54089f4bcb518409",
|
"rev": "fcf90c0c4d368b2ca917a7afa6d08e98a397e5fd",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -37,11 +37,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1774386573,
|
"lastModified": 1775710090,
|
||||||
"narHash": "sha256-4hAV26quOxdC6iyG7kYaZcM3VOskcPUrdCQd/nx8obc=",
|
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "46db2e09e1d3f113a13c0d7b81e2f221c63b8ce9",
|
"rev": "4c1018dae018162ec878d42fec712642d214fdfa",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -61,11 +61,11 @@
|
|||||||
"rust-analyzer-src": {
|
"rust-analyzer-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1774569884,
|
"lastModified": 1775745684,
|
||||||
"narHash": "sha256-E8iWEPzg7OnE0XXXjo75CX7xFauqzJuGZ5wSO9KS8Ek=",
|
"narHash": "sha256-8MbfLwd60FNa8dRFkjE+G3TT/x21G3Rsplm1bMBQUtU=",
|
||||||
"owner": "rust-lang",
|
"owner": "rust-lang",
|
||||||
"repo": "rust-analyzer",
|
"repo": "rust-analyzer",
|
||||||
"rev": "443ddcddd0c73b07b799d052f5ef3b448c2f3508",
|
"rev": "64ddb549bc9a70d011328746fa46a8883f937b6b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -26,23 +26,16 @@
|
|||||||
"rustfmt"
|
"rustfmt"
|
||||||
"rust-analyzer"
|
"rust-analyzer"
|
||||||
])
|
])
|
||||||
cargo-outdated
|
|
||||||
cargo-machete
|
cargo-machete
|
||||||
|
cargo-bloat
|
||||||
lldb
|
lldb
|
||||||
valgrind
|
valgrind
|
||||||
hyperfine
|
hyperfine
|
||||||
just
|
just
|
||||||
samply
|
samply
|
||||||
jq
|
|
||||||
tokei
|
tokei
|
||||||
|
|
||||||
nodejs
|
|
||||||
nodePackages.npm
|
|
||||||
biome
|
|
||||||
|
|
||||||
claude-code
|
claude-code
|
||||||
codex
|
|
||||||
opencode
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user