clean up
This commit is contained in:
@@ -16,9 +16,6 @@ vim.lsp.config("rust_analyzer", {
|
||||
settings = {
|
||||
["rust-analyzer"] = {
|
||||
cargo = {
|
||||
features = {
|
||||
"inspector"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1078
Cargo.lock
generated
1078
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,7 @@
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = [
|
||||
"nix-js",
|
||||
"nix-js-macros"
|
||||
"fix"
|
||||
]
|
||||
|
||||
[profile.profiling]
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
[package]
|
||||
name = "nix-js"
|
||||
name = "fix"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
mimalloc = "0.1"
|
||||
@@ -35,9 +34,6 @@ itertools = "0.14"
|
||||
|
||||
regex = "1.11"
|
||||
|
||||
deno_core = "0.385"
|
||||
deno_error = "0.7"
|
||||
|
||||
nix-nar = "0.3"
|
||||
sha2 = "0.10"
|
||||
sha1 = "0.10"
|
||||
@@ -54,7 +50,7 @@ bzip2 = "0.6"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
# spec 1.0.0
|
||||
toml = "0.9.9"
|
||||
toml = "=0.9.9"
|
||||
dirs = "6.0"
|
||||
tempfile = "3.24"
|
||||
rusqlite = { version = "0.38", features = ["bundled"] }
|
||||
@@ -62,24 +58,15 @@ rusqlite = { version = "0.38", features = ["bundled"] }
|
||||
rnix = "0.14"
|
||||
rowan = "0.16"
|
||||
|
||||
nix-js-macros = { path = "../nix-js-macros" }
|
||||
ere = "0.2.4"
|
||||
num_enum = "0.7.5"
|
||||
tap = "1.0.1"
|
||||
|
||||
# Inspector (optional)
|
||||
fastwebsockets = { version = "0.10", features = ["upgrade"], optional = true }
|
||||
hyper = { version = "1", features = ["http1", "server"], optional = true }
|
||||
hyper-util = { version = "0.1", features = ["tokio"], optional = true }
|
||||
http-body-util = { version = "0.1", optional = true }
|
||||
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 = []
|
||||
ghost-cell = "0.2"
|
||||
colored = "3.1"
|
||||
boxing = "0.1"
|
||||
gc-arena = { version = "0.5.3", features = ["allocator-api2"] }
|
||||
allocator-api2 = "0.4.0"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.8", features = ["html_reports"] }
|
||||
@@ -96,7 +83,3 @@ harness = false
|
||||
[[bench]]
|
||||
name = "thunk_scope"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "compile_time"
|
||||
harness = false
|
||||
@@ -1,8 +1,8 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use nix_js::context::Context;
|
||||
use nix_js::error::{Result, Source};
|
||||
use nix_js::value::Value;
|
||||
use fix::context::Context;
|
||||
use fix::error::{Result, Source};
|
||||
use fix::value::Value;
|
||||
|
||||
pub fn eval(expr: &str) -> Value {
|
||||
Context::new()
|
||||
@@ -16,10 +16,3 @@ pub fn eval_result(expr: &str) -> Result<Value> {
|
||||
.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()
|
||||
}
|
||||
@@ -30,72 +30,72 @@ pub(crate) trait BytecodeContext {
|
||||
#[derive(Clone, Copy, TryFromPrimitive)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub enum Op {
|
||||
PushConst = 0x01,
|
||||
PushString = 0x02,
|
||||
PushNull = 0x03,
|
||||
PushTrue = 0x04,
|
||||
PushFalse = 0x05,
|
||||
PushConst,
|
||||
PushString,
|
||||
PushNull,
|
||||
PushTrue,
|
||||
PushFalse,
|
||||
|
||||
LoadLocal = 0x06,
|
||||
LoadOuter = 0x07,
|
||||
StoreLocal = 0x08,
|
||||
AllocLocals = 0x09,
|
||||
LoadLocal,
|
||||
LoadOuter,
|
||||
StoreLocal,
|
||||
AllocLocals,
|
||||
|
||||
MakeThunk = 0x0A,
|
||||
MakeClosure = 0x0B,
|
||||
MakePatternClosure = 0x0C,
|
||||
MakeThunk,
|
||||
MakeClosure,
|
||||
MakePatternClosure,
|
||||
|
||||
Call = 0x0D,
|
||||
CallNoSpan = 0x0E,
|
||||
Call,
|
||||
CallNoSpan,
|
||||
|
||||
MakeAttrs = 0x0F,
|
||||
MakeAttrsDyn = 0x10,
|
||||
MakeEmptyAttrs = 0x11,
|
||||
Select = 0x12,
|
||||
SelectDefault = 0x13,
|
||||
HasAttr = 0x14,
|
||||
MakeAttrs,
|
||||
MakeAttrsDyn,
|
||||
MakeEmptyAttrs,
|
||||
Select,
|
||||
SelectDefault,
|
||||
HasAttr,
|
||||
|
||||
MakeList = 0x15,
|
||||
MakeList,
|
||||
|
||||
OpAdd = 0x16,
|
||||
OpSub = 0x17,
|
||||
OpMul = 0x18,
|
||||
OpDiv = 0x19,
|
||||
OpEq = 0x20,
|
||||
OpNeq = 0x21,
|
||||
OpLt = 0x22,
|
||||
OpGt = 0x23,
|
||||
OpLeq = 0x24,
|
||||
OpGeq = 0x25,
|
||||
OpConcat = 0x26,
|
||||
OpUpdate = 0x27,
|
||||
OpAdd,
|
||||
OpSub,
|
||||
OpMul,
|
||||
OpDiv,
|
||||
OpEq,
|
||||
OpNeq,
|
||||
OpLt,
|
||||
OpGt,
|
||||
OpLeq,
|
||||
OpGeq,
|
||||
OpConcat,
|
||||
OpUpdate,
|
||||
|
||||
OpNeg = 0x28,
|
||||
OpNot = 0x29,
|
||||
OpNeg,
|
||||
OpNot,
|
||||
|
||||
ForceBool = 0x30,
|
||||
JumpIfFalse = 0x31,
|
||||
JumpIfTrue = 0x32,
|
||||
Jump = 0x33,
|
||||
ForceBool,
|
||||
JumpIfFalse,
|
||||
JumpIfTrue,
|
||||
Jump,
|
||||
|
||||
ConcatStrings = 0x34,
|
||||
ResolvePath = 0x35,
|
||||
ConcatStrings,
|
||||
ResolvePath,
|
||||
|
||||
Assert = 0x36,
|
||||
Assert,
|
||||
|
||||
PushWith = 0x37,
|
||||
PopWith = 0x38,
|
||||
WithLookup = 0x39,
|
||||
PushWith,
|
||||
PopWith,
|
||||
WithLookup,
|
||||
|
||||
LoadBuiltins = 0x40,
|
||||
LoadBuiltin = 0x41,
|
||||
LoadBuiltins,
|
||||
LoadBuiltin,
|
||||
|
||||
MkPos = 0x43,
|
||||
MkPos,
|
||||
|
||||
LoadReplBinding = 0x44,
|
||||
LoadScopedBinding = 0x45,
|
||||
LoadReplBinding,
|
||||
LoadScopedBinding,
|
||||
|
||||
Return = 0x46,
|
||||
Return,
|
||||
}
|
||||
|
||||
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> {
|
||||
fn new(ctx: &'a mut Ctx) -> 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<'_>)]) {
|
||||
for &(id, inner) in thunks {
|
||||
let label = format!("e{}", id.0);
|
||||
@@ -9,14 +9,10 @@ use rnix::TextRange;
|
||||
use string_interner::DefaultStringInterner;
|
||||
|
||||
use crate::bytecode::{self, Bytecode, BytecodeContext, Constant};
|
||||
use crate::codegen::{CodegenContext, compile};
|
||||
use crate::disassembler::{Disassembler, DisassemblerContext};
|
||||
use crate::downgrade::*;
|
||||
use crate::error::{Error, Result, Source};
|
||||
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::value::{Symbol, Value};
|
||||
|
||||
@@ -48,129 +44,27 @@ fn handle_parse_error<'a>(
|
||||
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 {
|
||||
pub fn new() -> Result<Self> {
|
||||
let ctx = Ctx::new()?;
|
||||
#[cfg(feature = "inspector")]
|
||||
let runtime = Runtime::new(Default::default())?;
|
||||
#[cfg(not(feature = "inspector"))]
|
||||
let runtime = Runtime::new()?;
|
||||
|
||||
let mut context = Self {
|
||||
ctx,
|
||||
runtime,
|
||||
#[cfg(feature = "inspector")]
|
||||
_inspector_server: None,
|
||||
};
|
||||
context.init()?;
|
||||
|
||||
Ok(context)
|
||||
pub fn eval(&mut self, _source: Source) -> Result<Value> {
|
||||
todo!()
|
||||
}
|
||||
pub fn eval_shallow(&mut self, _source: Source) -> Result<Value> {
|
||||
todo!()
|
||||
}
|
||||
pub fn eval_deep(&mut self, _source: Source) -> Result<Value> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[cfg(feature = "inspector")]
|
||||
pub fn new_with_inspector(addr: std::net::SocketAddr, wait_for_session: bool) -> Result<Self> {
|
||||
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 eval_repl<'a>(&'a mut self, _source: Source, _scope: &'a HashSet<SymId>) -> Result<Value> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
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 {
|
||||
Disassembler::new(bytecode, &self.ctx).disassemble_colored()
|
||||
}
|
||||
|
||||
pub fn get_store_dir(&self) -> &str {
|
||||
self.ctx.get_store_dir()
|
||||
Disassembler::new(bytecode, self).disassemble_colored()
|
||||
}
|
||||
|
||||
pub fn add_binding<'a>(
|
||||
@@ -179,22 +73,11 @@ impl Context {
|
||||
expr: &str,
|
||||
scope: &'a mut HashSet<SymId>,
|
||||
) -> Result<Value> {
|
||||
let source = Source::new_repl(expr.to_string())?;
|
||||
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)
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
struct Ctx {
|
||||
pub struct Context {
|
||||
symbols: DefaultStringInterner,
|
||||
global: HashMap<SymId, Ir<'static, RawIrRef<'static>>>,
|
||||
sources: Vec<Source>,
|
||||
@@ -226,8 +109,8 @@ impl OwnedIr {
|
||||
}
|
||||
}
|
||||
|
||||
impl Ctx {
|
||||
fn new() -> Result<Self> {
|
||||
impl Context {
|
||||
pub fn new() -> Result<Self> {
|
||||
let mut symbols = DefaultStringInterner::new();
|
||||
let mut global = HashMap::new();
|
||||
let builtins_sym = symbols.get_or_intern("builtins");
|
||||
@@ -349,33 +232,7 @@ impl Ctx {
|
||||
})
|
||||
}
|
||||
|
||||
fn compile<'ctx>(
|
||||
&'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> {
|
||||
pub fn compile_bytecode(&mut self, source: Source) -> Result<Bytecode> {
|
||||
let root = self.downgrade(source, None)?;
|
||||
tracing::debug!("Generating bytecode");
|
||||
let bytecode = bytecode::compile_bytecode(root.as_ref(), self);
|
||||
@@ -383,47 +240,12 @@ impl Ctx {
|
||||
Ok(bytecode)
|
||||
}
|
||||
|
||||
fn compile_bytecode_scoped(&mut self, source: Source, scope: Vec<String>) -> Result<Bytecode> {
|
||||
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 {
|
||||
pub fn get_store_dir(&self) -> &str {
|
||||
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 {
|
||||
if let Some(&idx) = self.global_string_map.get(s) {
|
||||
return idx;
|
||||
@@ -445,7 +267,16 @@ impl BytecodeContext for Ctx {
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -453,51 +284,11 @@ impl BytecodeContext for Ctx {
|
||||
}
|
||||
|
||||
fn get_current_dir(&self) -> &Path {
|
||||
Ctx::get_current_dir(self)
|
||||
Context::get_current_dir(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl RuntimeContext for Ctx {
|
||||
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 {
|
||||
impl DisassemblerContext for Context {
|
||||
fn lookup_string(&self, id: u32) -> &str {
|
||||
self.global_strings
|
||||
.get(id as usize)
|
||||
@@ -1,14 +1,9 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_core::error::JsError;
|
||||
use deno_error::JsErrorClass as _;
|
||||
use itertools::Itertools as _;
|
||||
use miette::{Diagnostic, NamedSource, SourceSpan};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::runtime::RuntimeContext;
|
||||
|
||||
pub type Result<T> = core::result::Result<T, Box<Error>>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -229,127 +224,3 @@ pub struct StackFrame {
|
||||
#[source_code]
|
||||
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()
|
||||
}
|
||||
@@ -5,8 +5,6 @@ use nix_compat::nixhash::HashAlgo;
|
||||
use nix_compat::nixhash::NixHash;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::runtime::OpStateExt;
|
||||
use crate::runtime::RuntimeContext;
|
||||
use crate::store::Store as _;
|
||||
|
||||
mod archive;
|
||||
@@ -20,7 +18,6 @@ pub use download::Downloader;
|
||||
pub use metadata_cache::MetadataCache;
|
||||
|
||||
use crate::nar;
|
||||
use crate::runtime::NixRuntimeError;
|
||||
|
||||
#[derive(ToV8)]
|
||||
pub struct FetchUrlResult {
|
||||
@@ -306,11 +303,3 @@ fn normalize_hash(hash: &str) -> 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>(),
|
||||
]
|
||||
}
|
||||
@@ -10,7 +10,7 @@ impl FetcherCache {
|
||||
pub fn new() -> Result<Self, std::io::Error> {
|
||||
let base_dir = dirs::cache_dir()
|
||||
.unwrap_or_else(|| PathBuf::from("/tmp"))
|
||||
.join("nix-js")
|
||||
.join("fix")
|
||||
.join("fetchers");
|
||||
|
||||
fs::create_dir_all(&base_dir)?;
|
||||
@@ -6,11 +6,10 @@ pub mod logging;
|
||||
pub mod value;
|
||||
|
||||
mod bytecode;
|
||||
mod codegen;
|
||||
mod derivation;
|
||||
mod disassembler;
|
||||
mod downgrade;
|
||||
mod fetcher;
|
||||
// mod fetcher;
|
||||
mod ir;
|
||||
mod nar;
|
||||
mod nix_utils;
|
||||
@@ -4,22 +4,14 @@ use std::process::exit;
|
||||
use anyhow::Result;
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use hashbrown::HashSet;
|
||||
use nix_js::context::Context;
|
||||
use nix_js::error::Source;
|
||||
use fix::context::Context;
|
||||
use fix::error::Source;
|
||||
use rustyline::DefaultEditor;
|
||||
use rustyline::error::ReadlineError;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "nix-js", about = "Nix expression evaluator")]
|
||||
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: Command,
|
||||
}
|
||||
@@ -48,27 +40,6 @@ struct ExprSource {
|
||||
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<()> {
|
||||
let src = if let Some(expr) = src.expr {
|
||||
Source::new_eval(expr)?
|
||||
@@ -88,8 +59,6 @@ fn run_compile(context: &mut Context, src: ExprSource, silent: bool) -> Result<(
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "inspector")]
|
||||
context.wait_for_inspector_disconnect();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -110,8 +79,6 @@ fn run_eval(context: &mut Context, src: ExprSource) -> Result<()> {
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "inspector")]
|
||||
context.wait_for_inspector_disconnect();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -170,14 +137,11 @@ fn run_repl(context: &mut Context) -> Result<()> {
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
nix_js::logging::init_logging();
|
||||
fix::logging::init_logging();
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
let mut context = create_context(
|
||||
#[cfg(feature = "inspector")]
|
||||
&cli,
|
||||
)?;
|
||||
let mut context = Context::new()?;
|
||||
|
||||
match cli.command {
|
||||
Command::Compile { source, silent } => run_compile(&mut context, source, silent),
|
||||
@@ -1,4 +1,4 @@
|
||||
use nix_js::value::Value;
|
||||
use fix::value::Value;
|
||||
|
||||
use crate::utils::{eval, eval_result};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use nix_js::value::{AttrSet, List, Value};
|
||||
use fix::value::{AttrSet, List, Value};
|
||||
|
||||
use crate::utils::eval;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use nix_js::value::Value;
|
||||
use fix::value::Value;
|
||||
|
||||
use crate::utils::eval_result;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use nix_js::value::Value;
|
||||
use fix::value::Value;
|
||||
|
||||
use crate::utils::{eval_deep, eval_deep_result};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use nix_js::value::{List, Value};
|
||||
use fix::value::{List, Value};
|
||||
|
||||
use crate::utils::{eval, eval_result};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use nix_js::value::Value;
|
||||
use fix::value::Value;
|
||||
|
||||
use crate::utils::{eval, eval_result};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use nix_js::context::Context;
|
||||
use nix_js::error::Source;
|
||||
use nix_js::value::Value;
|
||||
use fix::context::Context;
|
||||
use fix::error::Source;
|
||||
use fix::value::Value;
|
||||
|
||||
use crate::utils::{eval, eval_result};
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use nix_js::context::Context;
|
||||
use nix_js::error::Source;
|
||||
use nix_js::value::Value;
|
||||
use fix::context::Context;
|
||||
use fix::error::Source;
|
||||
use fix::value::Value;
|
||||
|
||||
fn get_lang_dir() -> PathBuf {
|
||||
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 source = Source {
|
||||
ty: nix_js::error::SourceType::File(nix_path.into()),
|
||||
ty: fix::error::SourceType::File(nix_path.into()),
|
||||
src: expr.into(),
|
||||
};
|
||||
ctx.eval_deep(source.clone())
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user