This commit is contained in:
2026-03-12 17:47:46 +08:00
parent 7a7229d70e
commit 0c9a391618
511 changed files with 234 additions and 12772 deletions

View File

@@ -16,9 +16,6 @@ vim.lsp.config("rust_analyzer", {
settings = { settings = {
["rust-analyzer"] = { ["rust-analyzer"] = {
cargo = { cargo = {
features = {
"inspector"
}
} }
} }
} }

1078
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,7 @@
[workspace] [workspace]
resolver = "3" resolver = "3"
members = [ members = [
"nix-js", "fix"
"nix-js-macros"
] ]
[profile.profiling] [profile.profiling]

View File

@@ -1,8 +1,7 @@
[package] [package]
name = "nix-js" name = "fix"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
build = "build.rs"
[dependencies] [dependencies]
mimalloc = "0.1" mimalloc = "0.1"
@@ -35,9 +34,6 @@ itertools = "0.14"
regex = "1.11" regex = "1.11"
deno_core = "0.385"
deno_error = "0.7"
nix-nar = "0.3" nix-nar = "0.3"
sha2 = "0.10" sha2 = "0.10"
sha1 = "0.10" sha1 = "0.10"
@@ -54,7 +50,7 @@ bzip2 = "0.6"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
# spec 1.0.0 # spec 1.0.0
toml = "0.9.9" toml = "=0.9.9"
dirs = "6.0" dirs = "6.0"
tempfile = "3.24" tempfile = "3.24"
rusqlite = { version = "0.38", features = ["bundled"] } rusqlite = { version = "0.38", features = ["bundled"] }
@@ -62,24 +58,15 @@ rusqlite = { version = "0.38", features = ["bundled"] }
rnix = "0.14" rnix = "0.14"
rowan = "0.16" rowan = "0.16"
nix-js-macros = { path = "../nix-js-macros" }
ere = "0.2.4" ere = "0.2.4"
num_enum = "0.7.5" num_enum = "0.7.5"
tap = "1.0.1" tap = "1.0.1"
# Inspector (optional) ghost-cell = "0.2"
fastwebsockets = { version = "0.10", features = ["upgrade"], optional = true } colored = "3.1"
hyper = { version = "1", features = ["http1", "server"], optional = true } boxing = "0.1"
hyper-util = { version = "0.1", features = ["tokio"], optional = true } gc-arena = { version = "0.5.3", features = ["allocator-api2"] }
http-body-util = { version = "0.1", optional = true } allocator-api2 = "0.4.0"
http = { version = "1", optional = true }
uuid = { version = "1", features = ["v4"], optional = true }
ghost-cell = "0.2.6"
colored = "3.1.1"
[features]
inspector = ["dep:fastwebsockets", "dep:hyper", "dep:hyper-util", "dep:http-body-util", "dep:http", "dep:uuid"]
prof = []
[dev-dependencies] [dev-dependencies]
criterion = { version = "0.8", features = ["html_reports"] } criterion = { version = "0.8", features = ["html_reports"] }
@@ -96,7 +83,3 @@ harness = false
[[bench]] [[bench]]
name = "thunk_scope" name = "thunk_scope"
harness = false harness = false
[[bench]]
name = "compile_time"
harness = false

View File

@@ -1,8 +1,8 @@
#![allow(dead_code)] #![allow(dead_code)]
use nix_js::context::Context; use fix::context::Context;
use nix_js::error::{Result, Source}; use fix::error::{Result, Source};
use nix_js::value::Value; use fix::value::Value;
pub fn eval(expr: &str) -> Value { pub fn eval(expr: &str) -> Value {
Context::new() Context::new()
@@ -16,10 +16,3 @@ pub fn eval_result(expr: &str) -> Result<Value> {
.unwrap() .unwrap()
.eval(Source::new_eval(expr.into()).unwrap()) .eval(Source::new_eval(expr.into()).unwrap())
} }
pub fn compile(expr: &str) -> String {
Context::new()
.unwrap()
.compile(Source::new_eval(expr.into()).unwrap())
.unwrap()
}

View File

@@ -30,72 +30,72 @@ pub(crate) trait BytecodeContext {
#[derive(Clone, Copy, TryFromPrimitive)] #[derive(Clone, Copy, TryFromPrimitive)]
#[allow(clippy::enum_variant_names)] #[allow(clippy::enum_variant_names)]
pub enum Op { pub enum Op {
PushConst = 0x01, PushConst,
PushString = 0x02, PushString,
PushNull = 0x03, PushNull,
PushTrue = 0x04, PushTrue,
PushFalse = 0x05, PushFalse,
LoadLocal = 0x06, LoadLocal,
LoadOuter = 0x07, LoadOuter,
StoreLocal = 0x08, StoreLocal,
AllocLocals = 0x09, AllocLocals,
MakeThunk = 0x0A, MakeThunk,
MakeClosure = 0x0B, MakeClosure,
MakePatternClosure = 0x0C, MakePatternClosure,
Call = 0x0D, Call,
CallNoSpan = 0x0E, CallNoSpan,
MakeAttrs = 0x0F, MakeAttrs,
MakeAttrsDyn = 0x10, MakeAttrsDyn,
MakeEmptyAttrs = 0x11, MakeEmptyAttrs,
Select = 0x12, Select,
SelectDefault = 0x13, SelectDefault,
HasAttr = 0x14, HasAttr,
MakeList = 0x15, MakeList,
OpAdd = 0x16, OpAdd,
OpSub = 0x17, OpSub,
OpMul = 0x18, OpMul,
OpDiv = 0x19, OpDiv,
OpEq = 0x20, OpEq,
OpNeq = 0x21, OpNeq,
OpLt = 0x22, OpLt,
OpGt = 0x23, OpGt,
OpLeq = 0x24, OpLeq,
OpGeq = 0x25, OpGeq,
OpConcat = 0x26, OpConcat,
OpUpdate = 0x27, OpUpdate,
OpNeg = 0x28, OpNeg,
OpNot = 0x29, OpNot,
ForceBool = 0x30, ForceBool,
JumpIfFalse = 0x31, JumpIfFalse,
JumpIfTrue = 0x32, JumpIfTrue,
Jump = 0x33, Jump,
ConcatStrings = 0x34, ConcatStrings,
ResolvePath = 0x35, ResolvePath,
Assert = 0x36, Assert,
PushWith = 0x37, PushWith,
PopWith = 0x38, PopWith,
WithLookup = 0x39, WithLookup,
LoadBuiltins = 0x40, LoadBuiltins,
LoadBuiltin = 0x41, LoadBuiltin,
MkPos = 0x43, MkPos,
LoadReplBinding = 0x44, LoadReplBinding,
LoadScopedBinding = 0x45, LoadScopedBinding,
Return = 0x46, Return,
} }
struct ScopeInfo { struct ScopeInfo {
@@ -120,19 +120,6 @@ pub(crate) fn compile_bytecode(ir: RawIrRef<'_>, ctx: &mut impl BytecodeContext)
} }
} }
pub(crate) fn compile_bytecode_scoped(
ir: RawIrRef<'_>,
ctx: &mut impl BytecodeContext,
) -> Bytecode {
let current_dir = ctx.get_current_dir().to_string_lossy().to_string();
let mut emitter = BytecodeEmitter::new(ctx);
emitter.emit_toplevel_scoped(ir);
Bytecode {
code: emitter.code.into_boxed_slice(),
current_dir,
}
}
impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
fn new(ctx: &'a mut Ctx) -> Self { fn new(ctx: &'a mut Ctx) -> Self {
Self { Self {
@@ -397,37 +384,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
} }
} }
fn emit_toplevel_scoped(&mut self, ir: RawIrRef<'_>) {
match ir.deref() {
Ir::TopLevel { body, thunks } => {
let with_thunk_count = self.count_with_thunks(*body);
let total_slots = thunks.len() + with_thunk_count;
let all_thunks = self.collect_all_thunks(thunks, *body);
let thunk_ids: Vec<ThunkId> = all_thunks.iter().map(|&(id, _)| id).collect();
self.push_scope(false, None, &thunk_ids);
if total_slots > 0 {
self.emit_op(Op::AllocLocals);
self.emit_u32(total_slots as u32);
}
self.emit_scope_thunks(thunks);
self.emit_expr(*body);
self.emit_op(Op::Return);
self.pop_scope();
}
_ => {
self.push_scope(false, None, &[]);
self.emit_expr(ir);
self.emit_op(Op::Return);
self.pop_scope();
}
}
}
fn emit_scope_thunks(&mut self, thunks: &[(ThunkId, RawIrRef<'_>)]) { fn emit_scope_thunks(&mut self, thunks: &[(ThunkId, RawIrRef<'_>)]) {
for &(id, inner) in thunks { for &(id, inner) in thunks {
let label = format!("e{}", id.0); let label = format!("e{}", id.0);

View File

@@ -9,14 +9,10 @@ use rnix::TextRange;
use string_interner::DefaultStringInterner; use string_interner::DefaultStringInterner;
use crate::bytecode::{self, Bytecode, BytecodeContext, Constant}; use crate::bytecode::{self, Bytecode, BytecodeContext, Constant};
use crate::codegen::{CodegenContext, compile};
use crate::disassembler::{Disassembler, DisassemblerContext}; use crate::disassembler::{Disassembler, DisassemblerContext};
use crate::downgrade::*; use crate::downgrade::*;
use crate::error::{Error, Result, Source}; use crate::error::{Error, Result, Source};
use crate::ir::{ArgId, Ir, IrKey, IrRef, RawIrRef, SymId, ThunkId, ir_content_eq}; use crate::ir::{ArgId, Ir, IrKey, IrRef, RawIrRef, SymId, ThunkId, ir_content_eq};
#[cfg(feature = "inspector")]
use crate::runtime::inspector::InspectorServer;
use crate::runtime::{ForceMode, Runtime, RuntimeContext};
use crate::store::{DaemonStore, Store, StoreConfig}; use crate::store::{DaemonStore, Store, StoreConfig};
use crate::value::{Symbol, Value}; use crate::value::{Symbol, Value};
@@ -48,129 +44,27 @@ fn handle_parse_error<'a>(
None None
} }
pub struct Context {
ctx: Ctx,
runtime: Runtime<Ctx>,
#[cfg(feature = "inspector")]
_inspector_server: Option<InspectorServer>,
}
macro_rules! eval_bc {
($name:ident, $mode:expr) => {
pub fn $name(&mut self, source: Source) -> Result<Value> {
tracing::info!("Starting evaluation");
tracing::debug!("Compiling bytecode");
let bytecode = self.ctx.compile_bytecode(source)?;
tracing::debug!("Executing bytecode");
self.runtime.eval_bytecode(bytecode, &mut self.ctx, $mode)
}
};
}
impl Context { impl Context {
pub fn new() -> Result<Self> { pub fn eval(&mut self, _source: Source) -> Result<Value> {
let ctx = Ctx::new()?; todo!()
#[cfg(feature = "inspector")] }
let runtime = Runtime::new(Default::default())?; pub fn eval_shallow(&mut self, _source: Source) -> Result<Value> {
#[cfg(not(feature = "inspector"))] todo!()
let runtime = Runtime::new()?; }
pub fn eval_deep(&mut self, _source: Source) -> Result<Value> {
let mut context = Self { todo!()
ctx,
runtime,
#[cfg(feature = "inspector")]
_inspector_server: None,
};
context.init()?;
Ok(context)
} }
#[cfg(feature = "inspector")] pub fn eval_repl<'a>(&'a mut self, _source: Source, _scope: &'a HashSet<SymId>) -> Result<Value> {
pub fn new_with_inspector(addr: std::net::SocketAddr, wait_for_session: bool) -> Result<Self> { todo!()
use crate::runtime::InspectorOptions;
let ctx = Ctx::new()?;
let runtime = Runtime::new(InspectorOptions {
enable: true,
wait: wait_for_session,
})?;
let server = crate::runtime::inspector::InspectorServer::new(addr, "nix-js")
.map_err(|e| Error::internal(e.to_string()))?;
server.register_inspector("nix-js".to_string(), runtime.inspector(), wait_for_session);
let mut context = Self {
ctx,
runtime,
_inspector_server: Some(server),
};
context.init()?;
Ok(context)
}
#[cfg(feature = "inspector")]
pub fn wait_for_inspector_disconnect(&mut self) {
self.runtime.wait_for_inspector_disconnect();
}
fn init(&mut self) -> Result<()> {
const DERIVATION_NIX: &str = include_str!("runtime/corepkgs/derivation.nix");
let source = Source::new_virtual(
"<nix/derivation-internal.nix>".into(),
DERIVATION_NIX.to_string(),
);
let code = self.ctx.compile(source, None)?;
self.runtime.eval(
format!(
"Nix.builtins.set('derivation',({}));Nix.builtins.set('storeDir','{}');{}0n",
code,
self.get_store_dir(),
if std::env::var("NIX_JS_DEBUG_THUNKS").is_ok() {
"Nix.DEBUG_THUNKS.enabled=true;"
} else {
""
}
),
&mut self.ctx,
)?;
Ok(())
}
eval_bc!(eval, ForceMode::Force);
eval_bc!(eval_shallow, ForceMode::ForceShallow);
eval_bc!(eval_deep, ForceMode::ForceDeep);
pub fn eval_repl<'a>(&'a mut self, source: Source, scope: &'a HashSet<SymId>) -> Result<Value> {
tracing::info!("Starting evaluation");
tracing::debug!("Compiling code");
let code = self.ctx.compile(source, Some(Scope::Repl(scope)))?;
tracing::debug!("Executing JavaScript");
self.runtime
.eval(format!("Nix.forceShallow({})", code), &mut self.ctx)
}
pub fn compile(&mut self, source: Source) -> Result<String> {
self.ctx.compile(source, None)
}
pub fn compile_bytecode(&mut self, source: Source) -> Result<Bytecode> {
self.ctx.compile_bytecode(source)
} }
pub fn disassemble(&self, bytecode: &Bytecode) -> String { pub fn disassemble(&self, bytecode: &Bytecode) -> String {
Disassembler::new(bytecode, &self.ctx).disassemble() Disassembler::new(bytecode, self).disassemble()
} }
pub fn disassemble_colored(&self, bytecode: &Bytecode) -> String { pub fn disassemble_colored(&self, bytecode: &Bytecode) -> String {
Disassembler::new(bytecode, &self.ctx).disassemble_colored() Disassembler::new(bytecode, self).disassemble_colored()
}
pub fn get_store_dir(&self) -> &str {
self.ctx.get_store_dir()
} }
pub fn add_binding<'a>( pub fn add_binding<'a>(
@@ -179,22 +73,11 @@ impl Context {
expr: &str, expr: &str,
scope: &'a mut HashSet<SymId>, scope: &'a mut HashSet<SymId>,
) -> Result<Value> { ) -> Result<Value> {
let source = Source::new_repl(expr.to_string())?; todo!()
let code = self.ctx.compile(source, Some(Scope::Repl(scope)))?;
let sym = self.ctx.symbols.get_or_intern(name);
let eval_and_store = format!(
"(()=>{{const __v=Nix.forceShallow({});Nix.setReplBinding(\"{}\",__v);return __v}})()",
code, name
);
scope.insert(sym);
self.runtime.eval(eval_and_store, &mut self.ctx)
} }
} }
struct Ctx { pub struct Context {
symbols: DefaultStringInterner, symbols: DefaultStringInterner,
global: HashMap<SymId, Ir<'static, RawIrRef<'static>>>, global: HashMap<SymId, Ir<'static, RawIrRef<'static>>>,
sources: Vec<Source>, sources: Vec<Source>,
@@ -226,8 +109,8 @@ impl OwnedIr {
} }
} }
impl Ctx { impl Context {
fn new() -> Result<Self> { pub fn new() -> Result<Self> {
let mut symbols = DefaultStringInterner::new(); let mut symbols = DefaultStringInterner::new();
let mut global = HashMap::new(); let mut global = HashMap::new();
let builtins_sym = symbols.get_or_intern("builtins"); let builtins_sym = symbols.get_or_intern("builtins");
@@ -349,33 +232,7 @@ impl Ctx {
}) })
} }
fn compile<'ctx>( pub fn compile_bytecode(&mut self, source: Source) -> Result<Bytecode> {
&'ctx mut self,
source: Source,
extra_scope: Option<Scope<'ctx>>,
) -> Result<String> {
let root = self.downgrade(source, extra_scope)?;
tracing::debug!("Generating JavaScript code");
let code = compile::<false>(root.as_ref(), self);
tracing::debug!("Generated code: {}", &code);
Ok(code)
}
fn compile_scoped(&mut self, source: Source, scope: Vec<String>) -> Result<String> {
let scope = Scope::ScopedImport(
scope
.into_iter()
.map(|k| self.symbols.get_or_intern(k))
.collect(),
);
let root = self.downgrade(source, Some(scope))?;
tracing::debug!("Generating JavaScript code for scoped import");
let code = compile::<true>(root.as_ref(), self);
tracing::debug!("Generated scoped code: {}", &code);
Ok(code)
}
fn compile_bytecode(&mut self, source: Source) -> Result<Bytecode> {
let root = self.downgrade(source, None)?; let root = self.downgrade(source, None)?;
tracing::debug!("Generating bytecode"); tracing::debug!("Generating bytecode");
let bytecode = bytecode::compile_bytecode(root.as_ref(), self); let bytecode = bytecode::compile_bytecode(root.as_ref(), self);
@@ -383,47 +240,12 @@ impl Ctx {
Ok(bytecode) Ok(bytecode)
} }
fn compile_bytecode_scoped(&mut self, source: Source, scope: Vec<String>) -> Result<Bytecode> { pub fn get_store_dir(&self) -> &str {
let scope = Scope::ScopedImport(
scope
.into_iter()
.map(|k| self.symbols.get_or_intern(k))
.collect(),
);
let root = self.downgrade(source, Some(scope))?;
tracing::debug!("Generating bytecode for scoped import");
Ok(bytecode::compile_bytecode_scoped(root.as_ref(), self))
}
}
impl CodegenContext for Ctx {
fn get_sym(&self, id: SymId) -> Symbol<'_> {
self.symbols
.resolve(id)
.expect("SymId out of bounds")
.into()
}
fn get_current_dir(&self) -> &std::path::Path {
self.get_current_dir()
}
fn get_current_source_id(&self) -> usize {
self.sources
.len()
.checked_sub(1)
.expect("current_source not set")
}
fn get_store_dir(&self) -> &str {
self.store.get_store_dir() self.store.get_store_dir()
} }
fn register_span(&self, range: rnix::TextRange) -> usize {
let spans = unsafe { &mut *self.spans.get() };
let id = spans.len();
spans.push((self.get_current_source_id(), range));
id
}
} }
impl BytecodeContext for Ctx { impl BytecodeContext for Context {
fn intern_string(&mut self, s: &str) -> u32 { fn intern_string(&mut self, s: &str) -> u32 {
if let Some(&idx) = self.global_string_map.get(s) { if let Some(&idx) = self.global_string_map.get(s) {
return idx; return idx;
@@ -445,7 +267,16 @@ impl BytecodeContext for Ctx {
} }
fn register_span(&self, range: TextRange) -> u32 { fn register_span(&self, range: TextRange) -> u32 {
CodegenContext::register_span(self, range) as u32 // FIXME: SAFETY
let spans = unsafe { &mut *self.spans.get() };
let id = spans.len();
let source_id = self
.sources
.len()
.checked_sub(1)
.expect("current_source not set");
spans.push((source_id, range));
id as u32
} }
fn get_sym(&self, id: SymId) -> &str { fn get_sym(&self, id: SymId) -> &str {
@@ -453,51 +284,11 @@ impl BytecodeContext for Ctx {
} }
fn get_current_dir(&self) -> &Path { fn get_current_dir(&self) -> &Path {
Ctx::get_current_dir(self) Context::get_current_dir(self)
} }
} }
impl RuntimeContext for Ctx { impl DisassemblerContext for Context {
fn get_current_dir(&self) -> &Path {
self.get_current_dir()
}
fn add_source(&mut self, source: Source) {
self.sources.push(source);
}
fn compile(&mut self, source: Source) -> Result<String> {
self.compile(source, None)
}
fn compile_scoped(&mut self, source: Source, scope: Vec<String>) -> Result<String> {
self.compile_scoped(source, scope)
}
fn compile_bytecode(&mut self, source: Source) -> Result<Bytecode> {
self.compile_bytecode(source)
}
fn compile_bytecode_scoped(&mut self, source: Source, scope: Vec<String>) -> Result<Bytecode> {
self.compile_bytecode_scoped(source, scope)
}
fn get_source(&self, id: usize) -> Source {
self.sources.get(id).expect("source not found").clone()
}
fn get_store(&self) -> &DaemonStore {
&self.store
}
fn get_span(&self, id: usize) -> (usize, TextRange) {
let spans = unsafe { &*self.spans.get() };
spans[id]
}
fn get_unsynced(&mut self) -> (&[String], &[Constant], usize, usize) {
let strings_base = self.synced_strings;
let constants_base = self.synced_constants;
let new_strings = &self.global_strings[strings_base..];
let new_constants = &self.global_constants[constants_base..];
self.synced_strings = self.global_strings.len();
self.synced_constants = self.global_constants.len();
(new_strings, new_constants, strings_base, constants_base)
}
}
impl DisassemblerContext for Ctx {
fn lookup_string(&self, id: u32) -> &str { fn lookup_string(&self, id: u32) -> &str {
self.global_strings self.global_strings
.get(id as usize) .get(id as usize)

View File

@@ -1,14 +1,9 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use deno_core::error::JsError;
use deno_error::JsErrorClass as _;
use itertools::Itertools as _;
use miette::{Diagnostic, NamedSource, SourceSpan}; use miette::{Diagnostic, NamedSource, SourceSpan};
use thiserror::Error; use thiserror::Error;
use crate::runtime::RuntimeContext;
pub type Result<T> = core::result::Result<T, Box<Error>>; pub type Result<T> = core::result::Result<T, Box<Error>>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -229,127 +224,3 @@ pub struct StackFrame {
#[source_code] #[source_code]
pub src: NamedSource<Arc<str>>, pub src: NamedSource<Arc<str>>,
} }
const MAX_STACK_FRAMES: usize = 20;
const FRAMES_AT_START: usize = 15;
const FRAMES_AT_END: usize = 5;
pub(crate) fn parse_js_error(error: Box<JsError>, ctx: &impl RuntimeContext) -> Error {
let (span, src, frames) = if let Some(stack) = &error.stack {
let mut frames = parse_frames(stack, ctx);
if let Some(last_frame) = frames.pop() {
(
Some(text_range_to_source_span(last_frame.span)),
Some(last_frame.src.into()),
frames,
)
} else {
(None, None, frames)
}
} else {
(None, None, Vec::new())
};
let stack_trace = if std::env::var("NIX_JS_STACK_TRACE").is_ok() {
truncate_stack_trace(frames)
} else {
Vec::new()
};
let message = error.get_message().to_string();
let js_backtrace = error.stack.map(|stack| {
stack
.lines()
.filter(|line| !line.starts_with("NIX_STACK_FRAME:"))
.join("\n")
});
Error::EvalError {
src,
span,
message,
js_backtrace,
stack_trace,
}
}
struct NixStackFrame {
span: rnix::TextRange,
message: String,
src: Source,
}
impl From<NixStackFrame> for StackFrame {
fn from(NixStackFrame { span, message, src }: NixStackFrame) -> Self {
StackFrame {
span: text_range_to_source_span(span),
message,
src: src.into(),
}
}
}
fn parse_frames(stack: &str, ctx: &impl RuntimeContext) -> Vec<NixStackFrame> {
let mut frames = Vec::new();
for line in stack.lines() {
// Format: NIX_STACK_FRAME:span_id:message
let Some(rest) = line.strip_prefix("NIX_STACK_FRAME:") else {
continue;
};
let parts: Vec<&str> = rest.splitn(2, ':').collect();
if parts.is_empty() {
continue;
}
let span_id: usize = match parts[0].parse() {
Ok(id) => id,
Err(_) => continue,
};
let (source_id, span) = ctx.get_span(span_id);
let src = ctx.get_source(source_id);
let message = if parts.len() == 2 {
parts[1].to_string()
} else {
String::new()
};
frames.push(NixStackFrame { span, message, src });
}
frames.dedup_by(|a, b| a.span == b.span && a.message == b.message);
frames
}
fn truncate_stack_trace(frames: Vec<NixStackFrame>) -> Vec<StackFrame> {
let reversed: Vec<_> = frames.into_iter().rev().collect();
let total = reversed.len();
if total <= MAX_STACK_FRAMES {
return reversed.into_iter().map(Into::into).collect();
}
let omitted_count = total - FRAMES_AT_START - FRAMES_AT_END;
reversed
.into_iter()
.enumerate()
.filter_map(|(i, frame)| {
if i < FRAMES_AT_START {
Some(frame.into())
} else if i == FRAMES_AT_START {
Some(StackFrame {
span: text_range_to_source_span(frame.span),
message: format!("... ({} more frames omitted)", omitted_count),
src: frame.src.into(),
})
} else if i >= total - FRAMES_AT_END {
Some(frame.into())
} else {
None
}
})
.collect()
}

View File

@@ -5,8 +5,6 @@ use nix_compat::nixhash::HashAlgo;
use nix_compat::nixhash::NixHash; use nix_compat::nixhash::NixHash;
use tracing::{debug, info, warn}; use tracing::{debug, info, warn};
use crate::runtime::OpStateExt;
use crate::runtime::RuntimeContext;
use crate::store::Store as _; use crate::store::Store as _;
mod archive; mod archive;
@@ -20,7 +18,6 @@ pub use download::Downloader;
pub use metadata_cache::MetadataCache; pub use metadata_cache::MetadataCache;
use crate::nar; use crate::nar;
use crate::runtime::NixRuntimeError;
#[derive(ToV8)] #[derive(ToV8)]
pub struct FetchUrlResult { pub struct FetchUrlResult {
@@ -306,11 +303,3 @@ fn normalize_hash(hash: &str) -> String {
} }
hash.to_string() hash.to_string()
} }
pub fn register_ops<Ctx: RuntimeContext>() -> Vec<deno_core::OpDecl> {
vec![
op_fetch_url::<Ctx>(),
op_fetch_tarball::<Ctx>(),
op_fetch_git::<Ctx>(),
]
}

View File

@@ -10,7 +10,7 @@ impl FetcherCache {
pub fn new() -> Result<Self, std::io::Error> { pub fn new() -> Result<Self, std::io::Error> {
let base_dir = dirs::cache_dir() let base_dir = dirs::cache_dir()
.unwrap_or_else(|| PathBuf::from("/tmp")) .unwrap_or_else(|| PathBuf::from("/tmp"))
.join("nix-js") .join("fix")
.join("fetchers"); .join("fetchers");
fs::create_dir_all(&base_dir)?; fs::create_dir_all(&base_dir)?;

View File

@@ -6,11 +6,10 @@ pub mod logging;
pub mod value; pub mod value;
mod bytecode; mod bytecode;
mod codegen;
mod derivation; mod derivation;
mod disassembler; mod disassembler;
mod downgrade; mod downgrade;
mod fetcher; // mod fetcher;
mod ir; mod ir;
mod nar; mod nar;
mod nix_utils; mod nix_utils;

View File

@@ -4,22 +4,14 @@ use std::process::exit;
use anyhow::Result; use anyhow::Result;
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
use hashbrown::HashSet; use hashbrown::HashSet;
use nix_js::context::Context; use fix::context::Context;
use nix_js::error::Source; use fix::error::Source;
use rustyline::DefaultEditor; use rustyline::DefaultEditor;
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
#[derive(Parser)] #[derive(Parser)]
#[command(name = "nix-js", about = "Nix expression evaluator")] #[command(name = "nix-js", about = "Nix expression evaluator")]
struct Cli { struct Cli {
#[cfg(feature = "inspector")]
#[arg(long, value_name = "HOST:PORT", num_args = 0..=1, default_missing_value = "127.0.0.1:9229")]
inspect: Option<String>,
#[cfg(feature = "inspector")]
#[arg(long, value_name = "HOST:PORT", num_args = 0..=1, default_missing_value = "127.0.0.1:9229")]
inspect_brk: Option<String>,
#[command(subcommand)] #[command(subcommand)]
command: Command, command: Command,
} }
@@ -48,27 +40,6 @@ struct ExprSource {
file: Option<PathBuf>, file: Option<PathBuf>,
} }
fn create_context(#[cfg(feature = "inspector")] cli: &Cli) -> Result<Context> {
#[cfg(feature = "inspector")]
{
let (addr_str, wait) = if let Some(ref addr) = cli.inspect_brk {
(Some(addr.as_str()), true)
} else if let Some(ref addr) = cli.inspect {
(Some(addr.as_str()), false)
} else {
(None, false)
};
if let Some(addr_str) = addr_str {
let addr: std::net::SocketAddr = addr_str
.parse()
.map_err(|e| anyhow::anyhow!("invalid inspector address '{}': {}", addr_str, e))?;
return Ok(Context::new_with_inspector(addr, wait)?);
}
}
Ok(Context::new()?)
}
fn run_compile(context: &mut Context, src: ExprSource, silent: bool) -> Result<()> { fn run_compile(context: &mut Context, 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)?
@@ -88,8 +59,6 @@ fn run_compile(context: &mut Context, src: ExprSource, silent: bool) -> Result<(
exit(1); exit(1);
} }
}; };
#[cfg(feature = "inspector")]
context.wait_for_inspector_disconnect();
Ok(()) Ok(())
} }
@@ -110,8 +79,6 @@ fn run_eval(context: &mut Context, src: ExprSource) -> Result<()> {
exit(1); exit(1);
} }
}; };
#[cfg(feature = "inspector")]
context.wait_for_inspector_disconnect();
Ok(()) Ok(())
} }
@@ -170,14 +137,11 @@ fn run_repl(context: &mut Context) -> Result<()> {
} }
fn main() -> Result<()> { fn main() -> Result<()> {
nix_js::logging::init_logging(); fix::logging::init_logging();
let cli = Cli::parse(); let cli = Cli::parse();
let mut context = create_context( let mut context = Context::new()?;
#[cfg(feature = "inspector")]
&cli,
)?;
match cli.command { match cli.command {
Command::Compile { source, silent } => run_compile(&mut context, source, silent), Command::Compile { source, silent } => run_compile(&mut context, source, silent),

View File

@@ -1,4 +1,4 @@
use nix_js::value::Value; use fix::value::Value;
use crate::utils::{eval, eval_result}; use crate::utils::{eval, eval_result};

View File

@@ -1,6 +1,6 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use nix_js::value::{AttrSet, List, Value}; use fix::value::{AttrSet, List, Value};
use crate::utils::eval; use crate::utils::eval;

View File

@@ -1,4 +1,4 @@
use nix_js::value::Value; use fix::value::Value;
use crate::utils::eval_result; use crate::utils::eval_result;

View File

@@ -1,4 +1,4 @@
use nix_js::value::Value; use fix::value::Value;
use crate::utils::{eval_deep, eval_deep_result}; use crate::utils::{eval_deep, eval_deep_result};

View File

@@ -1,4 +1,4 @@
use nix_js::value::{List, Value}; use fix::value::{List, Value};
use crate::utils::{eval, eval_result}; use crate::utils::{eval, eval_result};

View File

@@ -1,4 +1,4 @@
use nix_js::value::Value; use fix::value::Value;
use crate::utils::{eval, eval_result}; use crate::utils::{eval, eval_result};

View File

@@ -1,6 +1,6 @@
use nix_js::context::Context; use fix::context::Context;
use nix_js::error::Source; use fix::error::Source;
use nix_js::value::Value; use fix::value::Value;
use crate::utils::{eval, eval_result}; use crate::utils::{eval, eval_result};

View File

@@ -2,9 +2,9 @@
use std::path::PathBuf; use std::path::PathBuf;
use nix_js::context::Context; use fix::context::Context;
use nix_js::error::Source; use fix::error::Source;
use nix_js::value::Value; use fix::value::Value;
fn get_lang_dir() -> PathBuf { fn get_lang_dir() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/tests/lang") PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/tests/lang")
@@ -18,7 +18,7 @@ fn eval_file(name: &str) -> Result<(Value, Source), String> {
let mut ctx = Context::new().map_err(|e| e.to_string())?; let mut ctx = Context::new().map_err(|e| e.to_string())?;
let source = Source { let source = Source {
ty: nix_js::error::SourceType::File(nix_path.into()), ty: fix::error::SourceType::File(nix_path.into()),
src: expr.into(), src: expr.into(),
}; };
ctx.eval_deep(source.clone()) ctx.eval_deep(source.clone())

Some files were not shown because too many files have changed in this diff Show More