difftreelog
refactor switch gc to gcmodule
in: master
39 files changed
.github/workflows/release.ymldiffbeforeafterboth--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -21,7 +21,7 @@
args: --all
cargo-release:
- if: startsWith(github.ref, 'refs/tags/')
+ if: startsWith(github.ref, 'refs/tags/') && !endsWith(github.ref, '-test')
needs: [test]
runs-on: ubuntu-latest
steps:
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,11 +1,6 @@
[workspace]
members = [
- "crates/jrsonnet-interner",
- "crates/jrsonnet-parser",
- "crates/jrsonnet-evaluator",
- "crates/jrsonnet-stdlib",
- "crates/jrsonnet-cli",
- "crates/jrsonnet-types",
+ "crates/*",
"bindings/jsonnet",
"cmds/jrsonnet",
]
bindings/jsonnet/Cargo.tomldiffbeforeafterboth--- a/bindings/jsonnet/Cargo.toml
+++ b/bindings/jsonnet/Cargo.toml
@@ -10,7 +10,7 @@
[dependencies]
jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.4.2" }
jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.4.2" }
-jrsonnet-gc = { version = "0.4.2", features = ["derive"] }
+gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" }
[lib]
crate-type = ["cdylib"]
bindings/jsonnet/src/native.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/native.rs
+++ b/bindings/jsonnet/src/native.rs
@@ -1,9 +1,10 @@
+use gcmodule::Cc;
use jrsonnet_evaluator::{
error::{Error, LocError},
+ gc::TraceBox,
native::{NativeCallback, NativeCallbackHandler},
EvaluationState, Val,
};
-use jrsonnet_gc::{unsafe_empty_trace, Finalize, Gc, Trace};
use jrsonnet_parser::{Param, ParamsDesc};
use std::{
ffi::{c_void, CStr},
@@ -18,16 +19,15 @@
success: *mut c_int,
) -> *mut Val;
+#[derive(gcmodule::Trace)]
struct JsonnetNativeCallbackHandler {
+ #[skip_trace]
ctx: *const c_void,
+ #[skip_trace]
cb: JsonnetNativeCallback,
-}
-impl Finalize for JsonnetNativeCallbackHandler {}
-unsafe impl Trace for JsonnetNativeCallbackHandler {
- unsafe_empty_trace!();
}
impl NativeCallbackHandler for JsonnetNativeCallbackHandler {
- fn call(&self, _from: Option<Rc<Path>>, args: &[Val]) -> Result<Val, LocError> {
+ fn call(&self, _from: Rc<Path>, args: &[Val]) -> Result<Val, LocError> {
let mut n_args = Vec::new();
for a in args {
n_args.push(Some(Box::new(a.clone())));
@@ -74,9 +74,9 @@
vm.add_native(
name,
- Gc::new(NativeCallback::new(
+ Cc::new(NativeCallback::new(
params,
- Box::new(JsonnetNativeCallbackHandler { ctx, cb }),
+ TraceBox(Box::new(JsonnetNativeCallbackHandler { ctx, cb })),
)),
)
}
bindings/jsonnet/src/val_make.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/val_make.rs
+++ b/bindings/jsonnet/src/val_make.rs
@@ -1,7 +1,7 @@
//! Create values in VM
+use gcmodule::Cc;
use jrsonnet_evaluator::{ArrValue, EvaluationState, ObjValue, Val};
-use jrsonnet_gc::Gc;
use std::{
ffi::CStr,
os::raw::{c_char, c_double, c_int},
@@ -38,7 +38,7 @@
#[no_mangle]
pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> *mut Val {
- Box::into_raw(Box::new(Val::Arr(ArrValue::Eager(Gc::new(Vec::new())))))
+ Box::into_raw(Box::new(Val::Arr(ArrValue::Eager(Cc::new(Vec::new())))))
}
#[no_mangle]
bindings/jsonnet/src/val_modify.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/val_modify.rs
+++ b/bindings/jsonnet/src/val_modify.rs
@@ -2,8 +2,8 @@
//! Only tested with variables, which haven't altered by code before appearing here
//! In jrsonnet every value is immutable, and this code is probally broken
+use gcmodule::Cc;
use jrsonnet_evaluator::{ArrValue, EvaluationState, LazyBinding, LazyVal, ObjMember, Val};
-use jrsonnet_gc::Gc;
use jrsonnet_parser::Visibility;
use std::{ffi::CStr, os::raw::c_char};
@@ -23,7 +23,7 @@
new.push(item);
}
new.push(LazyVal::new_resolved(val.clone()));
- *arr = Val::Arr(ArrValue::Lazy(Gc::new(new)));
+ *arr = Val::Arr(ArrValue::Lazy(Cc::new(new)));
}
_ => panic!("should receive array"),
}
cmds/jrsonnet/Cargo.tomldiffbeforeafterboth--- a/cmds/jrsonnet/Cargo.toml
+++ b/cmds/jrsonnet/Cargo.toml
@@ -17,6 +17,7 @@
jrsonnet-cli = { path = "../../crates/jrsonnet-cli", version = "0.4.2" }
mimallocator = { version = "0.1.3", optional = true }
thiserror = "1.0"
+gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" }
[dependencies.clap]
git = "https://github.com/clap-rs/clap"
cmds/jrsonnet/src/main.rsdiffbeforeafterboth--- a/cmds/jrsonnet/src/main.rs
+++ b/cmds/jrsonnet/src/main.rs
@@ -136,7 +136,7 @@
let val = if opts.input.exec {
state.evaluate_snippet_raw(
- PathBuf::from("args").into(),
+ PathBuf::from("<cmdline>").into(),
(&opts.input.input as &str).into(),
)?
} else if opts.input.input == "-" {
crates/jrsonnet-cli/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-cli/Cargo.toml
+++ b/crates/jrsonnet-cli/Cargo.toml
@@ -12,11 +12,7 @@
"explaining-traces",
] }
jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.4.2" }
-jrsonnet-gc = { version = "0.4.2", features = [
- "derive",
- "unstable-config",
- "unstable-stats",
-] }
+gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" }
[dependencies.clap]
git = "https://github.com/clap-rs/clap"
crates/jrsonnet-cli/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-cli/src/lib.rs
+++ b/crates/jrsonnet-cli/src/lib.rs
@@ -103,12 +103,6 @@
#[derive(Clap)]
#[clap(help_heading = "GARBAGE COLLECTION")]
pub struct GcOpts {
- /// Min bytes allocated to start garbage collection
- #[clap(long, default_value = "20000000")]
- gc_initial_threshold: usize,
- /// How much heap should grow after unsuccessful garbage collection
- #[clap(long)]
- gc_used_space_ratio: Option<f64>,
/// Do not skip gc on exit
#[clap(long)]
gc_collect_on_exit: bool,
@@ -122,32 +116,28 @@
gc_collect_before_printing_stats: bool,
}
impl GcOpts {
+ pub fn configure_global(&self) {
+ if !self.gc_collect_on_exit {
+ gcmodule::set_thread_collect_on_drop(false)
+ }
+ }
pub fn stats_printer(&self) -> Option<GcStatsPrinter> {
- self.gc_print_stats
- .then(|| GcStatsPrinter(self.gc_collect_before_printing_stats))
+ self.gc_print_stats.then(|| GcStatsPrinter {
+ collect_before_printing_stats: self.gc_collect_before_printing_stats,
+ })
}
- pub fn configure_global(&self) {
- jrsonnet_gc::configure(|config| {
- config.leak_on_drop = !self.gc_collect_on_exit;
- config.threshold = self.gc_initial_threshold;
- if let Some(used_space_ratio) = self.gc_used_space_ratio {
- config.used_space_ratio = used_space_ratio;
- }
- });
- }
}
-pub struct GcStatsPrinter(bool);
+
+pub struct GcStatsPrinter {
+ collect_before_printing_stats: bool,
+}
impl Drop for GcStatsPrinter {
fn drop(&mut self) {
- if self.0 {
- jrsonnet_gc::force_collect()
+ eprintln!("=== GC STATS ===");
+ if self.collect_before_printing_stats {
+ let collected = gcmodule::collect_thread_cycles();
+ eprintln!("Collected: {}", collected);
}
- eprintln!("=== GC STATS ===");
- jrsonnet_gc::configure(|c| {
- eprintln!("Final threshold: {:?}", c.threshold);
- });
- let stats = jrsonnet_gc::stats();
- eprintln!("Collections performed: {}", stats.collections_performed);
- eprintln!("Bytes still allocated: {}", stats.bytes_allocated);
+ eprintln!("Tracked: {}", gcmodule::count_thread_tracked())
}
}
crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -32,7 +32,7 @@
rustc-hash = "1.1.0"
thiserror = "1.0"
-jrsonnet-gc = { version = "0.4.2", features = ["derive"] }
+gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" }
[dependencies.anyhow]
version = "1.0"
@@ -53,7 +53,7 @@
# Explaining traces
[dependencies.annotate-snippets]
-version = "0.9.0"
+version = "0.9.1"
features = ["color"]
optional = true
crates/jrsonnet-evaluator/build.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/build.rs
+++ b/crates/jrsonnet-evaluator/build.rs
@@ -13,7 +13,6 @@
STDLIB_STR,
&ParserSettings {
file_name: PathBuf::from("std.jsonnet").into(),
- loc_data: true,
},
)
.expect("parse");
crates/jrsonnet-evaluator/src/builtin/format.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/format.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/format.rs
@@ -2,13 +2,12 @@
#![allow(clippy::too_many_arguments)]
use crate::{error::Error::*, throw, LocError, ObjValue, Result, Val};
-use jrsonnet_gc::Trace;
+use gcmodule::Trace;
use jrsonnet_interner::IStr;
use jrsonnet_types::ValType;
use thiserror::Error;
#[derive(Debug, Clone, Error, Trace)]
-#[trivially_drop]
pub enum FormatError {
#[error("truncated format code")]
TruncatedFormatCode,
crates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/manifest.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/manifest.rs
@@ -1,6 +1,6 @@
use crate::error::Error::*;
use crate::error::Result;
-use crate::push_frame;
+use crate::push_description_frame;
use crate::{throw, Val};
#[derive(PartialEq, Clone, Copy)]
@@ -103,8 +103,7 @@
buf.push_str(cur_padding);
escape_string_json_buf(&field, buf);
buf.push_str(": ");
- push_frame(
- None,
+ push_description_frame(
|| format!("field <{}> manifestification", field.clone()),
|| {
let value = obj.get(field.clone())?.unwrap();
crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -7,7 +7,7 @@
EvaluationState, FuncVal, IndexableVal, LazyVal, Val,
};
use format::{format_arr, format_obj};
-use jrsonnet_gc::Gc;
+use gcmodule::Cc;
use jrsonnet_interner::IStr;
use jrsonnet_parser::{ArgsDesc, ExprLocation};
use jrsonnet_types::ty;
@@ -24,7 +24,7 @@
pub fn std_format(str: IStr, vals: Val) -> Result<Val> {
push_frame(
- Some(&ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)),
+ &ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0),
|| format!("std.format of {}", str),
|| {
Ok(match vals {
@@ -68,7 +68,7 @@
}
}
-type Builtin = fn(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val>;
+type Builtin = fn(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result<Val>;
type BuiltinsType = HashMap<Box<str>, Builtin>;
@@ -136,7 +136,7 @@
};
}
-fn builtin_length(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_length(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "length", args, 1, [
0, x: ty!((string | object | array));
], {
@@ -154,7 +154,7 @@
})
}
-fn builtin_type(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_type(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "type", args, 1, [
0, x: ty!(any);
], {
@@ -162,11 +162,7 @@
})
}
-fn builtin_make_array(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_make_array(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "makeArray", args, 2, [
0, sz: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;
1, func: ty!(function) => Val::Func;
@@ -182,11 +178,7 @@
})
}
-fn builtin_codepoint(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_codepoint(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "codepoint", args, 1, [
0, str: ty!(char) => Val::Str;
], {
@@ -194,11 +186,7 @@
})
}
-fn builtin_object_fields_ex(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_object_fields_ex(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "objectFieldsEx", args, 2, [
0, obj: ty!(object) => Val::Obj;
1, inc_hidden: ty!(boolean) => Val::Bool;
@@ -208,11 +196,7 @@
})
}
-fn builtin_object_has_ex(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_object_has_ex(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "objectHasEx", args, 3, [
0, obj: ty!(object) => Val::Obj;
1, f: ty!(string) => Val::Str;
@@ -222,11 +206,7 @@
})
}
-fn builtin_parse_json(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_parse_json(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "parseJson", args, 1, [
0, s: ty!(string) => Val::Str;
], {
@@ -236,7 +216,7 @@
})
}
-fn builtin_slice(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_slice(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "slice", args, 4, [
0, indexable: ty!((string | array));
1, index: ty!((number | null));
@@ -252,7 +232,7 @@
})
}
-fn builtin_substr(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_substr(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "substr", args, 3, [
0, str: ty!(string) => Val::Str;
1, from: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;
@@ -263,11 +243,7 @@
})
}
-fn builtin_primitive_equals(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_primitive_equals(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "primitiveEquals", args, 2, [
0, a: ty!(any);
1, b: ty!(any);
@@ -276,7 +252,7 @@
})
}
-fn builtin_equals(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_equals(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "equals", args, 2, [
0, a: ty!(any);
1, b: ty!(any);
@@ -285,7 +261,7 @@
})
}
-fn builtin_modulo(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_modulo(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "modulo", args, 2, [
0, a: ty!(number) => Val::Num;
1, b: ty!(number) => Val::Num;
@@ -294,7 +270,7 @@
})
}
-fn builtin_mod(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_mod(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "mod", args, 2, [
0, a: ty!((number | string));
1, b: ty!(any);
@@ -303,7 +279,7 @@
})
}
-fn builtin_floor(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_floor(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "floor", args, 1, [
0, x: ty!(number) => Val::Num;
], {
@@ -311,7 +287,7 @@
})
}
-fn builtin_ceil(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_ceil(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "ceil", args, 1, [
0, x: ty!(number) => Val::Num;
], {
@@ -319,7 +295,7 @@
})
}
-fn builtin_log(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_log(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "log", args, 1, [
0, n: ty!(number) => Val::Num;
], {
@@ -327,7 +303,7 @@
})
}
-fn builtin_pow(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_pow(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "pow", args, 2, [
0, x: ty!(number) => Val::Num;
1, n: ty!(number) => Val::Num;
@@ -336,7 +312,7 @@
})
}
-fn builtin_sqrt(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_sqrt(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "sqrt", args, 1, [
0, x: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;
], {
@@ -344,7 +320,7 @@
})
}
-fn builtin_sin(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_sin(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "sin", args, 1, [
0, x: ty!(number) => Val::Num;
], {
@@ -352,7 +328,7 @@
})
}
-fn builtin_cos(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_cos(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "cos", args, 1, [
0, x: ty!(number) => Val::Num;
], {
@@ -360,7 +336,7 @@
})
}
-fn builtin_tan(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_tan(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "tan", args, 1, [
0, x: ty!(number) => Val::Num;
], {
@@ -368,7 +344,7 @@
})
}
-fn builtin_asin(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_asin(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "asin", args, 1, [
0, x: ty!(number) => Val::Num;
], {
@@ -376,7 +352,7 @@
})
}
-fn builtin_acos(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_acos(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "acos", args, 1, [
0, x: ty!(number) => Val::Num;
], {
@@ -384,7 +360,7 @@
})
}
-fn builtin_atan(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_atan(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "atan", args, 1, [
0, x: ty!(number) => Val::Num;
], {
@@ -392,7 +368,7 @@
})
}
-fn builtin_exp(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_exp(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "exp", args, 1, [
0, x: ty!(number) => Val::Num;
], {
@@ -411,7 +387,7 @@
}
}
-fn builtin_mantissa(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_mantissa(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "mantissa", args, 1, [
0, x: ty!(number) => Val::Num;
], {
@@ -419,7 +395,7 @@
})
}
-fn builtin_exponent(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_exponent(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "exponent", args, 1, [
0, x: ty!(number) => Val::Num;
], {
@@ -427,7 +403,7 @@
})
}
-fn builtin_ext_var(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_ext_var(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "extVar", args, 1, [
0, x: ty!(string) => Val::Str;
], {
@@ -435,15 +411,15 @@
})
}
-fn builtin_native(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_native(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "native", args, 1, [
0, x: ty!(string) => Val::Str;
], {
- Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Gc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or(UndefinedExternalFunction(x))?)
+ Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Cc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or(UndefinedExternalFunction(x))?)
})
}
-fn builtin_filter(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_filter(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "filter", args, 2, [
0, func: ty!(function) => Val::Func;
1, arr: ty!(array) => Val::Arr;
@@ -454,7 +430,7 @@
})
}
-fn builtin_map(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_map(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "map", args, 2, [
0, func: ty!(function) => Val::Func;
1, arr: ty!(array) => Val::Arr;
@@ -464,7 +440,7 @@
})
}
-fn builtin_flatmap(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_flatmap(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "flatMap", args, 2, [
0, func: ty!(function) => Val::Func;
1, arr: ty!((array | string));
@@ -498,7 +474,7 @@
})
}
-fn builtin_foldl(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_foldl(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "foldl", args, 3, [
0, func: ty!(function) => Val::Func;
1, arr: ty!(array) => Val::Arr;
@@ -512,7 +488,7 @@
})
}
-fn builtin_foldr(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_foldr(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "foldr", args, 3, [
0, func: ty!(function) => Val::Func;
1, arr: ty!(array) => Val::Arr;
@@ -527,11 +503,7 @@
}
#[allow(non_snake_case)]
-fn builtin_sort_impl(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_sort_impl(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "sort", args, 2, [
0, arr: ty!(array) => Val::Arr;
1, keyF: ty!(function) => Val::Func;
@@ -543,7 +515,7 @@
})
}
-fn builtin_format(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_format(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "format", args, 2, [
0, str: ty!(string) => Val::Str;
1, vals: ty!(any)
@@ -552,7 +524,7 @@
})
}
-fn builtin_range(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_range(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "range", args, 2, [
0, from: ty!(number) => Val::Num;
1, to: ty!(number) => Val::Num;
@@ -568,7 +540,7 @@
})
}
-fn builtin_char(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_char(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "char", args, 1, [
0, n: ty!(number) => Val::Num;
], {
@@ -580,11 +552,7 @@
})
}
-fn builtin_encode_utf8(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_encode_utf8(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "encodeUTF8", args, 1, [
0, str: ty!(string) => Val::Str;
], {
@@ -592,11 +560,7 @@
})
}
-fn builtin_decode_utf8(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_decode_utf8(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "decodeUTF8", args, 1, [
0, arr: ty!((Array<ubyte>)) => Val::Arr;
], {
@@ -609,7 +573,7 @@
})
}
-fn builtin_md5(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_md5(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "md5", args, 1, [
0, str: ty!(string) => Val::Str;
], {
@@ -617,24 +581,22 @@
})
}
-fn builtin_trace(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_trace(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "trace", args, 2, [
0, str: ty!(string) => Val::Str;
1, rest: ty!(any);
], {
eprint!("TRACE:");
- if let Some(loc) = loc {
with_state(|s|{
let locs = s.map_source_locations(&loc.0, &[loc.1]);
eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line);
});
- }
eprintln!(" {}", str);
Ok(rest)
})
}
-fn builtin_base64(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_base64(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "base64", args, 1, [
0, input: ty!((string | (Array<number>)));
], {
@@ -654,7 +616,7 @@
fn builtin_base64_decode_bytes(
context: Context,
- _loc: Option<&ExprLocation>,
+ _loc: &ExprLocation,
args: &ArgsDesc,
) -> Result<Val> {
parse_args!(context, "base64DecodeBytes", args, 1, [
@@ -669,11 +631,7 @@
})
}
-fn builtin_base64_decode(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_base64_decode(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "base64Decode", args, 1, [
0, input: ty!(string) => Val::Str;
], {
@@ -685,7 +643,7 @@
})
}
-fn builtin_join(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_join(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "join", args, 2, [
0, sep: ty!((string | array));
1, arr: ty!(array) => Val::Arr;
@@ -744,7 +702,7 @@
fn builtin_escape_string_json(
context: Context,
- _loc: Option<&ExprLocation>,
+ _loc: &ExprLocation,
args: &ArgsDesc,
) -> Result<Val> {
parse_args!(context, "escapeStringJson", args, 1, [
@@ -754,11 +712,7 @@
})
}
-fn builtin_manifest_json_ex(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_manifest_json_ex(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "manifestJsonEx", args, 2, [
0, value: ty!(any);
1, indent: ty!(string) => Val::Str;
@@ -772,7 +726,7 @@
fn builtin_manifest_yaml_doc(
context: Context,
- _loc: Option<&ExprLocation>,
+ _loc: &ExprLocation,
args: &ArgsDesc,
) -> Result<Val> {
parse_args!(context, "manifestYamlDoc", args, 2, [
@@ -786,7 +740,7 @@
})
}
-fn builtin_reverse(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_reverse(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "reverse", args, 1, [
0, value: ty!(array) => Val::Arr;
], {
@@ -794,7 +748,7 @@
})
}
-fn builtin_id(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_id(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "id", args, 1, [
0, v: ty!(any);
], {
@@ -802,11 +756,7 @@
})
}
-fn builtin_str_replace(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_str_replace(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "strReplace", args, 3, [
0, str: ty!(string) => Val::Str;
1, from: ty!(string) => Val::Str;
@@ -816,11 +766,7 @@
})
}
-fn builtin_splitlimit(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_splitlimit(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "splitLimit", args, 3, [
0, str: ty!(string) => Val::Str;
1, c: ty!(char) => Val::Str;
@@ -839,11 +785,7 @@
})
}
-fn builtin_ascii_upper(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_ascii_upper(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "asciiUpper", args, 1, [
0, str: ty!(string) => Val::Str;
], {
@@ -851,11 +793,7 @@
})
}
-fn builtin_ascii_lower(
- context: Context,
- _loc: Option<&ExprLocation>,
- args: &ArgsDesc,
-) -> Result<Val> {
+fn builtin_ascii_lower(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "asciiLower", args, 1, [
0, str: ty!(string) => Val::Str;
], {
@@ -863,7 +801,7 @@
})
}
-fn builtin_member(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_member(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "member", args, 2, [
0, arr: ty!((array | string));
1, x: ty!(any);
@@ -887,7 +825,7 @@
})
}
-fn builtin_count(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_count(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "count", args, 2, [
0, arr: ty!(array) => Val::Arr;
1, x: ty!(any);
@@ -905,7 +843,7 @@
pub fn call_builtin(
context: Context,
- loc: Option<&ExprLocation>,
+ loc: &ExprLocation,
name: &str,
args: &ArgsDesc,
) -> Result<Val> {
crates/jrsonnet-evaluator/src/builtin/sort.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/sort.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/sort.rs
@@ -2,9 +2,9 @@
error::{Error, LocError, Result},
throw, Context, FuncVal, Val,
};
-use jrsonnet_gc::{Finalize, Gc, Trace};
+use gcmodule::{Cc, Trace};
-#[derive(Debug, Clone, thiserror::Error, Trace, Finalize)]
+#[derive(Debug, Clone, thiserror::Error, Trace)]
pub enum SortError {
#[error("sort key should be string or number")]
SortKeyShouldBeStringOrNumber,
@@ -59,7 +59,7 @@
Ok(sort_type)
}
-pub fn sort(ctx: Context, values: Gc<Vec<Val>>, key_getter: &FuncVal) -> Result<Gc<Vec<Val>>> {
+pub fn sort(ctx: Context, values: Cc<Vec<Val>>, key_getter: &FuncVal) -> Result<Cc<Vec<Val>>> {
if values.len() <= 1 {
return Ok(values);
}
@@ -77,7 +77,7 @@
}),
SortKeyType::Unknown => unreachable!(),
};
- Ok(Gc::new(mvalues))
+ Ok(Cc::new(mvalues))
} else {
let mut vk = Vec::with_capacity(values.len());
for value in values.iter() {
@@ -98,6 +98,6 @@
}),
SortKeyType::Unknown => unreachable!(),
};
- Ok(Gc::new(vk.into_iter().map(|v| v.0).collect()))
+ Ok(Cc::new(vk.into_iter().map(|v| v.0).collect()))
}
}
crates/jrsonnet-evaluator/src/builtin/stdlib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/stdlib.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/stdlib.rs
@@ -15,7 +15,6 @@
jrsonnet_parser::parse(
jrsonnet_stdlib::STDLIB_STR,
&ParserSettings {
- loc_data: true,
file_name: PathBuf::from("std.jsonnet").into(),
},
)
crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/ctx.rs
+++ b/crates/jrsonnet-evaluator/src/ctx.rs
@@ -1,16 +1,15 @@
+use crate::cc_ptr_eq;
+use crate::gc::GcHashMap;
use crate::{
error::Error::*, map::LayeredHashMap, FutureWrapper, LazyBinding, LazyVal, ObjValue, Result,
Val,
};
-use jrsonnet_gc::{Gc, Trace};
+use gcmodule::{Cc, Trace};
use jrsonnet_interner::IStr;
-use rustc_hash::FxHashMap;
use std::fmt::Debug;
-use std::hash::BuildHasherDefault;
#[derive(Clone, Trace)]
-#[trivially_drop]
-pub struct ContextCreator(pub Context, pub FutureWrapper<FxHashMap<IStr, LazyBinding>>);
+pub struct ContextCreator(pub Context, pub FutureWrapper<GcHashMap<IStr, LazyBinding>>);
impl ContextCreator {
pub fn create(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<Context> {
self.0.clone().extend_unbound(
@@ -23,7 +22,6 @@
}
#[derive(Trace)]
-#[trivially_drop]
struct ContextInternals {
dollar: Option<ObjValue>,
this: Option<ObjValue>,
@@ -37,8 +35,7 @@
}
#[derive(Debug, Clone, Trace)]
-#[trivially_drop]
-pub struct Context(Gc<ContextInternals>);
+pub struct Context(Cc<ContextInternals>);
impl Context {
pub fn new_future() -> FutureWrapper<Self> {
FutureWrapper::new()
@@ -57,7 +54,7 @@
}
pub fn new() -> Self {
- Self(Gc::new(ContextInternals {
+ Self(Cc::new(ContextInternals {
dollar: None,
this: None,
super_obj: None,
@@ -84,19 +81,18 @@
}
pub fn with_var(self, name: IStr, value: Val) -> Self {
- let mut new_bindings =
- FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());
+ let mut new_bindings = GcHashMap::with_capacity(1);
new_bindings.insert(name, LazyVal::new_resolved(value));
self.extend(new_bindings, None, None, None)
}
pub fn with_this_super(self, new_this: ObjValue, new_super_obj: Option<ObjValue>) -> Self {
- self.extend(FxHashMap::default(), None, Some(new_this), new_super_obj)
+ self.extend(GcHashMap::new(), None, Some(new_this), new_super_obj)
}
pub fn extend(
self,
- new_bindings: FxHashMap<IStr, LazyVal>,
+ new_bindings: GcHashMap<IStr, LazyVal>,
new_dollar: Option<ObjValue>,
new_this: Option<ObjValue>,
new_super_obj: Option<ObjValue>,
@@ -110,30 +106,29 @@
} else {
ctx.bindings.clone().extend(new_bindings)
};
- Self(Gc::new(ContextInternals {
+ Self(Cc::new(ContextInternals {
dollar,
this,
super_obj,
bindings,
}))
}
- pub fn extend_bound(self, new_bindings: FxHashMap<IStr, LazyVal>) -> Self {
+ pub fn extend_bound(self, new_bindings: GcHashMap<IStr, LazyVal>) -> Self {
let new_this = self.0.this.clone();
let new_super_obj = self.0.super_obj.clone();
self.extend(new_bindings, None, new_this, new_super_obj)
}
pub fn extend_unbound(
self,
- new_bindings: FxHashMap<IStr, LazyBinding>,
+ new_bindings: GcHashMap<IStr, LazyBinding>,
new_dollar: Option<ObjValue>,
new_this: Option<ObjValue>,
new_super_obj: Option<ObjValue>,
) -> Result<Self> {
let this = new_this.or_else(|| self.0.this.clone());
let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());
- let mut new =
- FxHashMap::with_capacity_and_hasher(new_bindings.len(), BuildHasherDefault::default());
- for (k, v) in new_bindings.into_iter() {
+ let mut new = GcHashMap::with_capacity(new_bindings.len());
+ for (k, v) in new_bindings.0.into_iter() {
new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);
}
Ok(self.extend(new, new_dollar, this, super_obj))
@@ -152,6 +147,6 @@
impl PartialEq for Context {
fn eq(&self, other: &Self) -> bool {
- Gc::ptr_eq(&self.0, &other.0)
+ cc_ptr_eq(&self.0, &other.0)
}
}
crates/jrsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/dynamic.rs
+++ b/crates/jrsonnet-evaluator/src/dynamic.rs
@@ -1,11 +1,12 @@
-use jrsonnet_gc::{Gc, GcCell, Trace};
+use std::cell::RefCell;
+use gcmodule::{Cc, Trace};
+
#[derive(Clone, Trace)]
-#[trivially_drop]
-pub struct FutureWrapper<V: Trace + 'static>(pub Gc<GcCell<Option<V>>>);
+pub struct FutureWrapper<V: Trace + 'static>(pub Cc<RefCell<Option<V>>>);
impl<T: Trace + 'static> FutureWrapper<T> {
pub fn new() -> Self {
- Self(Gc::new(GcCell::new(None)))
+ Self(Cc::new(RefCell::new(None)))
}
pub fn fill(self, value: T) {
assert!(self.0.borrow().is_none(), "wrapper is filled already");
crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -1,5 +1,8 @@
-use crate::{Val, builtin::{format::FormatError, sort::SortError}, typed::TypeLocError};
-use jrsonnet_gc::Trace;
+use crate::{
+ builtin::{format::FormatError, sort::SortError},
+ typed::TypeLocError,
+};
+use gcmodule::Trace;
use jrsonnet_interner::IStr;
use jrsonnet_parser::{BinaryOpType, ExprLocation, UnaryOpType};
use jrsonnet_types::ValType;
@@ -10,7 +13,6 @@
use thiserror::Error;
#[derive(Error, Debug, Clone, Trace)]
-#[trivially_drop]
pub enum Error {
#[error("intrinsic not found: {0}")]
IntrinsicNotFound(IStr),
@@ -85,14 +87,15 @@
#[error("tried to import {1} from {0}, but imports is not supported")]
ImportNotSupported(PathBuf, PathBuf),
#[error(
- "syntax error, expected one of {}, got {:?}",
+ "syntax error: expected {}, got {:?}",
.error.expected,
.source_code.chars().nth(error.location.offset).map(|c| c.to_string()).unwrap_or_else(|| "EOF".into())
)]
ImportSyntaxError {
+ #[skip_trace]
path: Rc<Path>,
source_code: IStr,
- #[unsafe_ignore_trace]
+ #[skip_trace]
error: Box<jrsonnet_parser::ParseError>,
},
@@ -150,17 +153,14 @@
}
#[derive(Clone, Debug, Trace)]
-#[trivially_drop]
pub struct StackTraceElement {
pub location: Option<ExprLocation>,
pub desc: String,
}
#[derive(Debug, Clone, Trace)]
-#[trivially_drop]
pub struct StackTrace(pub Vec<StackTraceElement>);
#[derive(Debug, Clone, Trace)]
-#[trivially_drop]
pub struct LocError(Box<(Error, StackTrace)>);
impl LocError {
pub fn new(e: Error) -> Self {
crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -2,19 +2,18 @@
builtin::std_slice,
error::Error::*,
evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op},
+ gc::TraceBox,
push_frame, throw, with_state, ArrValue, Bindable, Context, ContextCreator, FuncDesc, FuncVal,
- FutureWrapper, LazyBinding, LazyVal, LazyValValue, ObjValue, ObjValueBuilder, ObjectAssertion,
- Result, Val,
+ FutureWrapper, GcHashMap, LazyBinding, LazyVal, LazyValValue, ObjValue,
+ ObjValueBuilder, ObjectAssertion, Result, Val,
};
-use jrsonnet_gc::{Gc, Trace};
+use gcmodule::{Cc, Trace};
use jrsonnet_interner::IStr;
use jrsonnet_parser::{
ArgsDesc, AssertStmt, BindSpec, CompSpec, Expr, ExprLocation, FieldMember, ForSpecData,
IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc,
};
use jrsonnet_types::ValType;
-use rustc_hash::{FxHashMap, FxHasher};
-use std::{collections::HashMap, hash::BuildHasherDefault};
pub mod operator;
pub fn evaluate_binding_in_future(
@@ -26,7 +25,6 @@
let params = params.clone();
#[derive(Trace)]
- #[trivially_drop]
struct LazyMethodBinding {
context_creator: FutureWrapper<Context>,
name: IStr,
@@ -44,15 +42,14 @@
}
}
- LazyVal::new(Box::new(LazyMethodBinding {
+ LazyVal::new(TraceBox(Box::new(LazyMethodBinding {
context_creator,
name: b.name.clone(),
params,
value: b.value.clone(),
- }))
+ })))
} else {
#[derive(Trace)]
- #[trivially_drop]
struct LazyNamedBinding {
context_creator: FutureWrapper<Context>,
name: IStr,
@@ -63,11 +60,11 @@
evaluate_named(self.context_creator.unwrap(), &self.value, self.name)
}
}
- LazyVal::new(Box::new(LazyNamedBinding {
+ LazyVal::new(TraceBox(Box::new(LazyNamedBinding {
context_creator,
name: b.name.clone(),
value: b.value,
- }))
+ })))
}
}
@@ -77,7 +74,6 @@
let params = params.clone();
#[derive(Trace)]
- #[trivially_drop]
struct BindableMethodLazyVal {
this: Option<ObjValue>,
super_obj: Option<ObjValue>,
@@ -99,7 +95,6 @@
}
#[derive(Trace)]
- #[trivially_drop]
struct BindableMethod {
context_creator: ContextCreator,
name: IStr,
@@ -108,30 +103,31 @@
}
impl Bindable for BindableMethod {
fn bind(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {
- Ok(LazyVal::new(Box::new(BindableMethodLazyVal {
- this,
- super_obj,
+ Ok(LazyVal::new(TraceBox(Box::new(
+ BindableMethodLazyVal {
+ this,
+ super_obj,
- context_creator: self.context_creator.clone(),
- name: self.name.clone(),
- params: self.params.clone(),
- value: self.value.clone(),
- })))
+ context_creator: self.context_creator.clone(),
+ name: self.name.clone(),
+ params: self.params.clone(),
+ value: self.value.clone(),
+ },
+ ))))
}
}
(
b.name.clone(),
- LazyBinding::Bindable(Gc::new(Box::new(BindableMethod {
+ LazyBinding::Bindable(Cc::new(TraceBox(Box::new(BindableMethod {
context_creator,
name: b.name.clone(),
params,
value: b.value.clone(),
- }))),
+ })))),
)
} else {
#[derive(Trace)]
- #[trivially_drop]
struct BindableNamedLazyVal {
this: Option<ObjValue>,
super_obj: Option<ObjValue>,
@@ -151,7 +147,6 @@
}
#[derive(Trace)]
- #[trivially_drop]
struct BindableNamed {
context_creator: ContextCreator,
name: IStr,
@@ -159,30 +154,32 @@
}
impl Bindable for BindableNamed {
fn bind(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {
- Ok(LazyVal::new(Box::new(BindableNamedLazyVal {
- this,
- super_obj,
+ Ok(LazyVal::new(TraceBox(Box::new(
+ BindableNamedLazyVal {
+ this,
+ super_obj,
- context_creator: self.context_creator.clone(),
- name: self.name.clone(),
- value: self.value.clone(),
- })))
+ context_creator: self.context_creator.clone(),
+ name: self.name.clone(),
+ value: self.value.clone(),
+ },
+ ))))
}
}
(
b.name.clone(),
- LazyBinding::Bindable(Gc::new(Box::new(BindableNamed {
+ LazyBinding::Bindable(Cc::new(TraceBox(Box::new(BindableNamed {
context_creator,
name: b.name.clone(),
value: b.value.clone(),
- }))),
+ })))),
)
}
}
pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val {
- Val::Func(Gc::new(FuncVal::Normal(FuncDesc {
+ Val::Func(Cc::new(FuncVal::Normal(FuncDesc {
name,
ctx,
params,
@@ -240,8 +237,7 @@
let future_this = FutureWrapper::new();
let context_creator = ContextCreator(context.clone(), new_bindings.clone());
{
- let mut bindings: FxHashMap<IStr, LazyBinding> =
- FxHashMap::with_capacity_and_hasher(members.len(), BuildHasherDefault::default());
+ let mut bindings: GcHashMap<IStr, LazyBinding> = GcHashMap::with_capacity(members.len());
for (n, b) in members
.iter()
.filter_map(|m| match m {
@@ -272,7 +268,6 @@
let name = name.unwrap();
#[derive(Trace)]
- #[trivially_drop]
struct ObjMemberBinding {
context_creator: ContextCreator,
value: LocExpr,
@@ -296,11 +291,11 @@
.with_add(*plus)
.with_visibility(*visibility)
.with_location(value.1.clone())
- .bindable(Box::new(ObjMemberBinding {
+ .bindable(TraceBox(Box::new(ObjMemberBinding {
context_creator: context_creator.clone(),
value: value.clone(),
name,
- }));
+ })));
}
Member::Field(FieldMember {
name,
@@ -314,7 +309,6 @@
}
let name = name.unwrap();
#[derive(Trace)]
- #[trivially_drop]
struct ObjMemberBinding {
context_creator: ContextCreator,
value: LocExpr,
@@ -339,17 +333,16 @@
.member(name.clone())
.hide()
.with_location(value.1.clone())
- .bindable(Box::new(ObjMemberBinding {
+ .bindable(TraceBox(Box::new(ObjMemberBinding {
context_creator: context_creator.clone(),
value: value.clone(),
params: params.clone(),
name,
- }));
+ })));
}
Member::BindStmt(_) => {}
Member::AssertStmt(stmt) => {
#[derive(Trace)]
- #[trivially_drop]
struct ObjectAssert {
context_creator: ContextCreator,
assert: AssertStmt,
@@ -364,10 +357,10 @@
evaluate_assert(ctx, &self.assert)
}
}
- builder.assert(Box::new(ObjectAssert {
+ builder.assert(TraceBox(Box::new(ObjectAssert {
context_creator: context_creator.clone(),
assert: stmt.clone(),
- }));
+ })));
}
}
}
@@ -385,11 +378,8 @@
evaluate_comp(context.clone(), &obj.compspecs, &mut |ctx| {
let new_bindings = FutureWrapper::new();
let context_creator = ContextCreator(context.clone(), new_bindings.clone());
- let mut bindings: FxHashMap<IStr, LazyBinding> =
- FxHashMap::with_capacity_and_hasher(
- obj.pre_locals.len() + obj.post_locals.len(),
- BuildHasherDefault::default(),
- );
+ let mut bindings: GcHashMap<IStr, LazyBinding> =
+ GcHashMap::with_capacity(obj.pre_locals.len() + obj.post_locals.len());
for (n, b) in obj
.pre_locals
.iter()
@@ -406,7 +396,6 @@
Val::Null => {}
Val::Str(n) => {
#[derive(Trace)]
- #[trivially_drop]
struct ObjCompBinding {
context: Context,
value: LocExpr,
@@ -418,12 +407,9 @@
_super_obj: Option<ObjValue>,
) -> Result<LazyVal> {
Ok(LazyVal::new_resolved(evaluate(
- self.context.clone().extend(
- FxHashMap::default(),
- None,
- this,
- None,
- ),
+ self.context
+ .clone()
+ .extend(GcHashMap::new(), None, this, None),
&self.value,
)?))
}
@@ -432,10 +418,10 @@
.member(n)
.with_location(obj.value.1.clone())
.with_add(obj.plus)
- .bindable(Box::new(ObjCompBinding {
+ .bindable(TraceBox(Box::new(ObjCompBinding {
context: ctx,
value: obj.value.clone(),
- }));
+ })));
}
v => throw!(FieldMustBeStringGot(v.value_type())),
}
@@ -454,7 +440,7 @@
context: Context,
value: &LocExpr,
args: &ArgsDesc,
- loc: Option<&ExprLocation>,
+ loc: &ExprLocation,
tailstrict: bool,
) -> Result<Val> {
let value = evaluate(context.clone(), value)?;
@@ -475,7 +461,7 @@
let value = &assertion.0;
let msg = &assertion.1;
let assertion_result = push_frame(
- value.1.as_ref(),
+ &value.1,
|| "assertion condition".to_owned(),
|| {
evaluate(context.clone(), value)?
@@ -484,7 +470,7 @@
)?;
if !assertion_result {
push_frame(
- value.1.as_ref(),
+ &value.1,
|| "assertion failure".to_owned(),
|| {
if let Some(msg) = msg {
@@ -534,8 +520,8 @@
BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, v1, *o, v2)?,
UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,
Var(name) => push_frame(
- loc.as_ref(),
- || format!("variable <{}>", name),
+ loc,
+ || format!("variable <{}> access", name),
|| context.binding(name.clone())?.evaluate(),
)?,
Index(value, index) => {
@@ -543,7 +529,7 @@
(Val::Obj(v), Val::Str(s)) => {
let sn = s.clone();
push_frame(
- loc.as_ref(),
+ loc,
|| format!("field <{}> access", sn),
|| {
if let Some(v) = v.get(s.clone())? {
@@ -591,10 +577,8 @@
}
}
LocalExpr(bindings, returned) => {
- let mut new_bindings: FxHashMap<IStr, LazyVal> = HashMap::with_capacity_and_hasher(
- bindings.len(),
- BuildHasherDefault::<FxHasher>::default(),
- );
+ let mut new_bindings: GcHashMap<IStr, LazyVal> =
+ GcHashMap::with_capacity(bindings.len());
let future_context = Context::new_future();
for b in bindings {
new_bindings.insert(
@@ -612,7 +596,6 @@
for item in items {
// TODO: Implement ArrValue::Lazy with same context for every element?
#[derive(Trace)]
- #[trivially_drop]
struct ArrayElement {
context: Context,
item: LocExpr,
@@ -622,10 +605,10 @@
evaluate(self.context, &self.item)
}
}
- out.push(LazyVal::new(Box::new(ArrayElement {
+ out.push(LazyVal::new(TraceBox(Box::new(ArrayElement {
context: context.clone(),
item: item.clone(),
- })));
+ }))));
}
Val::Arr(out.into())
}
@@ -635,26 +618,24 @@
out.push(evaluate(ctx, expr)?);
Ok(())
})?;
- Val::Arr(ArrValue::Eager(Gc::new(out)))
+ Val::Arr(ArrValue::Eager(Cc::new(out)))
}
Obj(body) => Val::Obj(evaluate_object(context, body)?),
ObjExtend(s, t) => evaluate_add_op(
&evaluate(context.clone(), s)?,
&Val::Obj(evaluate_object(context, t)?),
)?,
- Apply(value, args, tailstrict) => {
- evaluate_apply(context, value, args, loc.as_ref(), *tailstrict)?
- }
+ Apply(value, args, tailstrict) => evaluate_apply(context, value, args, loc, *tailstrict)?,
Function(params, body) => {
evaluate_method(context, "anonymous".into(), params.clone(), body.clone())
}
- Intrinsic(name) => Val::Func(Gc::new(FuncVal::Intrinsic(name.clone()))),
+ Intrinsic(name) => Val::Func(Cc::new(FuncVal::Intrinsic(name.clone()))),
AssertExpr(assert, returned) => {
evaluate_assert(context.clone(), assert)?;
evaluate(context, returned)?
}
ErrorStmt(e) => push_frame(
- loc.as_ref(),
+ loc,
|| "error statement".to_owned(),
|| {
throw!(RuntimeError(
@@ -668,7 +649,7 @@
cond_else,
} => {
if push_frame(
- loc.as_ref(),
+ loc,
|| "if condition".to_owned(),
|| evaluate(context.clone(), &cond.0)?.try_cast_bool("in if condition"),
)? {
@@ -703,23 +684,17 @@
std_slice(indexable.into_indexable()?, start, end, step)?
}
Import(path) => {
- let tmp = loc
- .clone()
- .expect("imports cannot be used without loc_data")
- .0;
+ let tmp = loc.clone().0;
let mut import_location = tmp.to_path_buf();
import_location.pop();
push_frame(
- loc.as_ref(),
+ loc,
|| format!("import {:?}", path),
|| with_state(|s| s.import_file(&import_location, path)),
)?
}
ImportStr(path) => {
- let tmp = loc
- .clone()
- .expect("imports cannot be used without loc_data")
- .0;
+ let tmp = loc.clone().0;
let mut import_location = tmp.to_path_buf();
import_location.pop();
Val::Str(with_state(|s| s.import_file_str(&import_location, path))?)
crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function.rs
+++ b/crates/jrsonnet-evaluator/src/function.rs
@@ -1,18 +1,13 @@
-use crate::{
- error::Error::*, evaluate, evaluate_named, throw, Context, FutureWrapper, LazyVal,
- LazyValValue, Result, Val,
-};
-use jrsonnet_gc::Trace;
+use crate::{Context, FutureWrapper, GcHashMap, LazyVal, LazyValValue, Result, Val, error::Error::*, evaluate, evaluate_named, gc::TraceBox, throw};
+use gcmodule::Trace;
use jrsonnet_interner::IStr;
use jrsonnet_parser::{ArgsDesc, LocExpr, ParamsDesc};
-use rustc_hash::FxHashMap;
-use std::{collections::HashMap, hash::BuildHasherDefault};
+use std::collections::HashMap;
const NO_DEFAULT_CONTEXT: &str =
"no default context set for call with defined default parameter value";
#[derive(Trace)]
-#[trivially_drop]
struct EvaluateLazyVal {
context: Context,
expr: LocExpr,
@@ -38,8 +33,7 @@
args: &ArgsDesc,
tailstrict: bool,
) -> Result<Context> {
- let mut passed_args =
- HashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default());
+ let mut passed_args = GcHashMap::with_capacity(params.len());
if args.unnamed.len() > params.len() {
throw!(TooManyArgsFunctionHas(params.len()))
}
@@ -53,10 +47,10 @@
if tailstrict {
LazyVal::new_resolved(evaluate(ctx.clone(), arg)?)
} else {
- LazyVal::new(Box::new(EvaluateLazyVal {
+ LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {
context: ctx.clone(),
expr: arg.clone(),
- }))
+ })))
},
);
filled_args += 1;
@@ -73,10 +67,10 @@
if tailstrict {
LazyVal::new_resolved(evaluate(ctx.clone(), value)?)
} else {
- LazyVal::new(Box::new(EvaluateLazyVal {
+ LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {
context: ctx.clone(),
expr: value.clone(),
- }))
+ })))
},
)
.is_some()
@@ -90,17 +84,13 @@
// Some args are unset, but maybe we have defaults for them
// Default values should be created in newly created context
let future_context = FutureWrapper::<Context>::new();
- let mut defaults = HashMap::with_capacity_and_hasher(
- params.len() - filled_args,
- BuildHasherDefault::default(),
- );
+ let mut defaults = GcHashMap::with_capacity(params.len() - filled_args);
for param in params.iter().filter(|p| p.1.is_some()) {
if passed_args.contains_key(¶m.0.clone()) {
continue;
}
#[derive(Trace)]
- #[trivially_drop]
struct LazyNamedBinding {
future_context: FutureWrapper<Context>,
name: IStr,
@@ -111,19 +101,19 @@
evaluate_named(self.future_context.unwrap(), &self.value, self.name)
}
}
- LazyVal::new(Box::new(LazyNamedBinding {
+ LazyVal::new(TraceBox(Box::new(LazyNamedBinding {
future_context: future_context.clone(),
name: param.0.clone(),
value: param.1.clone().unwrap(),
- }));
+ })));
defaults.insert(
param.0.clone(),
- LazyVal::new(Box::new(LazyNamedBinding {
+ LazyVal::new(TraceBox(Box::new(LazyNamedBinding {
future_context: future_context.clone(),
name: param.0.clone(),
value: param.1.clone().unwrap(),
- })),
+ }))),
);
filled_args += 1;
}
@@ -155,7 +145,7 @@
args: &HashMap<IStr, Val>,
tailstrict: bool,
) -> Result<Context> {
- let mut out = FxHashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default());
+ let mut out = GcHashMap::with_capacity(params.len());
let mut positioned_args = vec![None; params.0.len()];
for (name, val) in args.iter() {
let idx = params
@@ -185,7 +175,6 @@
let body_ctx = body_ctx.clone();
let default = default.clone();
#[derive(Trace)]
- #[trivially_drop]
struct EvaluateLazyVal {
body_ctx: Option<Context>,
default: LocExpr,
@@ -198,7 +187,10 @@
)
}
}
- LazyVal::new(Box::new(EvaluateLazyVal { body_ctx, default }))
+ LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {
+ body_ctx,
+ default,
+ })))
}
} else {
throw!(FunctionParameterNotBoundInCall(p.0.clone()));
@@ -215,7 +207,7 @@
params: &ParamsDesc,
args: &[Val],
) -> Result<Context> {
- let mut out = FxHashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default());
+ let mut out = GcHashMap::with_capacity(params.len());
let mut positioned_args = vec![None; params.0.len()];
for (id, arg) in args.iter().enumerate() {
if id >= params.len() {
@@ -243,7 +235,7 @@
($ctx: expr, $fn_name: expr, $args: expr, $total_args: expr, [
$($id: expr, $name: ident: $ty: expr $(=>$match: path)?);+ $(;)?
], $handler:block) => {{
- use $crate::{error::Error::*, throw, evaluate, push_frame, typed::CheckType};
+ use $crate::{error::Error::*, throw, evaluate, push_description_frame, typed::CheckType};
let args = $args;
if args.unnamed.len() + args.named.len() > $total_args {
@@ -263,7 +255,7 @@
} else {
&$args.unnamed[$id]
};
- let $name = push_frame(None, || format!("evaluating argument"), || {
+ let $name = push_description_frame(|| format!("evaluating builtin argument {}", stringify!($name)), || {
let value = evaluate($ctx.clone(), &$name)?;
$ty.check(&value)?;
Ok(value)
crates/jrsonnet-evaluator/src/gc.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-evaluator/src/gc.rs
@@ -0,0 +1,141 @@
+/// Macros to help deal with Gc
+use std::{
+ borrow::{Borrow, BorrowMut},
+ hash::BuildHasherDefault,
+ ops::{Deref, DerefMut},
+};
+
+use gcmodule::{Trace, Tracer};
+use rustc_hash::{FxHashMap, FxHashSet};
+
+/// Replacement for box, which assumes that the underlying type is [`Trace`]
+#[derive(Debug, Clone)]
+pub struct TraceBox<T: ?Sized>(pub Box<T>);
+
+impl<T: ?Sized + Trace> Trace for TraceBox<T> {
+ fn trace(&self, tracer: &mut Tracer) {
+ self.0.trace(tracer)
+ }
+
+ fn is_type_tracked() -> bool {
+ return true;
+ }
+}
+
+// TODO: Replace with CoerceUnsized
+impl<T: ?Sized> From<Box<T>> for TraceBox<T> {
+ fn from(inner: Box<T>) -> Self {
+ Self(inner)
+ }
+}
+
+impl<T: ?Sized> Deref for TraceBox<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+impl<T: Trace + ?Sized> DerefMut for TraceBox<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+impl<T: ?Sized> Borrow<T> for TraceBox<T> {
+ fn borrow(&self) -> &T {
+ &*self.0
+ }
+}
+
+impl<T: ?Sized> BorrowMut<T> for TraceBox<T> {
+ fn borrow_mut(&mut self) -> &mut T {
+ &mut *self.0
+ }
+}
+
+impl<T: ?Sized> AsRef<T> for TraceBox<T> {
+ fn as_ref(&self) -> &T {
+ &*self.0
+ }
+}
+
+impl<T: ?Sized> AsMut<T> for TraceBox<T> {
+ fn as_mut(&mut self) -> &mut T {
+ &mut *self.0
+ }
+}
+
+#[derive(Clone)]
+pub struct GcHashSet<V>(pub FxHashSet<V>);
+impl<V> GcHashSet<V> {
+ pub fn new() -> Self {
+ Self(Default::default())
+ }
+ pub fn with_capacity(capacity: usize) -> Self {
+ Self(FxHashSet::with_capacity_and_hasher(
+ capacity,
+ BuildHasherDefault::default(),
+ ))
+ }
+}
+impl<V> Trace for GcHashSet<V>
+where
+ V: Trace,
+{
+ fn trace(&self, tracer: &mut gcmodule::Tracer) {
+ for v in &self.0 {
+ v.trace(tracer);
+ }
+ }
+}
+impl<V> Deref for GcHashSet<V> {
+ type Target = FxHashSet<V>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+impl<V> DerefMut for GcHashSet<V> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+#[derive(Clone)]
+pub struct GcHashMap<K, V>(pub FxHashMap<K, V>);
+impl<K, V> GcHashMap<K, V> {
+ pub fn new() -> Self {
+ Self(Default::default())
+ }
+ pub fn with_capacity(capacity: usize) -> Self {
+ Self(FxHashMap::with_capacity_and_hasher(
+ capacity,
+ BuildHasherDefault::default(),
+ ))
+ }
+}
+impl<K, V> Trace for GcHashMap<K, V>
+where
+ K: Trace,
+ V: Trace,
+{
+ fn trace(&self, tracer: &mut gcmodule::Tracer) {
+ for (k, v) in &self.0 {
+ k.trace(tracer);
+ v.trace(tracer);
+ }
+ }
+}
+impl<K, V> Deref for GcHashMap<K, V> {
+ type Target = FxHashMap<K, V>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+impl<K, V> DerefMut for GcHashMap<K, V> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -25,30 +25,31 @@
use error::{Error::*, LocError, Result, StackTraceElement};
pub use evaluate::*;
pub use function::parse_function_call;
+use gc::{GcHashMap, TraceBox};
+use gcmodule::{Cc, Trace};
pub use import::*;
-use jrsonnet_gc::{Finalize, Gc, Trace};
pub use jrsonnet_interner::IStr;
use jrsonnet_parser::*;
use native::NativeCallback;
pub use obj::*;
-use rustc_hash::FxHashMap;
use std::{
cell::{Ref, RefCell, RefMut},
collections::HashMap,
fmt::Debug,
- hash::BuildHasherDefault,
path::{Path, PathBuf},
rc::Rc,
};
use trace::{location_to_offset, offset_to_location, CodeLocation, CompactFormat, TraceFormat};
pub use val::*;
+pub mod gc;
-pub trait Bindable: Trace {
+pub trait Bindable: Trace + 'static {
fn bind(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal>;
}
-#[derive(Trace, Finalize, Clone)]
+
+#[derive(Clone, Trace)]
pub enum LazyBinding {
- Bindable(Gc<Box<dyn Bindable>>),
+ Bindable(Cc<TraceBox<dyn Bindable>>),
Bound(LazyVal),
}
@@ -74,7 +75,7 @@
/// Used for s`td.extVar`
pub ext_vars: HashMap<IStr, Val>,
/// Used for ext.native
- pub ext_natives: HashMap<IStr, Gc<NativeCallback>>,
+ pub ext_natives: HashMap<IStr, Cc<NativeCallback>>,
/// TLA vars
pub tla_vars: HashMap<IStr, Val>,
/// Global variables are inserted in default context
@@ -172,19 +173,27 @@
EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))
}
pub(crate) fn push_frame<T>(
- e: Option<&ExprLocation>,
+ e: &ExprLocation,
frame_desc: impl FnOnce() -> String,
f: impl FnOnce() -> Result<T>,
) -> Result<T> {
with_state(|s| s.push(e, frame_desc, f))
}
+#[allow(dead_code)]
pub(crate) fn push_val_frame(
- e: Option<&ExprLocation>,
+ e: &ExprLocation,
frame_desc: impl FnOnce() -> String,
f: impl FnOnce() -> Result<Val>,
) -> Result<Val> {
- with_state(|s| s.push(e, frame_desc, f))
+ with_state(|s| s.push_val(e, frame_desc, f))
+}
+#[allow(dead_code)]
+pub(crate) fn push_description_frame<T>(
+ frame_desc: impl FnOnce() -> String,
+ f: impl FnOnce() -> Result<T>,
+) -> Result<T> {
+ with_state(|s| s.push_description(frame_desc, f))
}
/// Maintains stack trace and import resolution
@@ -201,7 +210,6 @@
&source_code,
&ParserSettings {
file_name: path.clone(),
- loc_data: true,
},
)
.map_err(|error| ImportSyntaxError {
@@ -246,7 +254,7 @@
ro_map.get(name).map(|value| value.source_code.clone())
}
pub fn map_source_locations(&self, file: &Path, locs: &[usize]) -> Vec<CodeLocation> {
- offset_to_location(&self.get_source(file).unwrap(), locs)
+ offset_to_location(&self.get_source(file).unwrap_or("".into()), locs)
}
pub fn map_from_source_location(
&self,
@@ -322,8 +330,7 @@
/// Creates context with all passed global variables
pub fn create_default_context(&self) -> Context {
let globals = &self.settings().globals;
- let mut new_bindings: FxHashMap<IStr, LazyVal> =
- FxHashMap::with_capacity_and_hasher(globals.len(), BuildHasherDefault::default());
+ let mut new_bindings = GcHashMap::with_capacity(globals.len());
for (name, value) in globals.iter() {
new_bindings.insert(name.clone(), LazyVal::new_resolved(value.clone()));
}
@@ -333,7 +340,7 @@
/// Executes code creating a new stack frame
pub fn push<T>(
&self,
- e: Option<&ExprLocation>,
+ e: &ExprLocation,
frame_desc: impl FnOnce() -> String,
f: impl FnOnce() -> Result<T>,
) -> Result<T> {
@@ -353,25 +360,21 @@
let mut data = self.data_mut();
data.stack_depth -= 1;
data.stack_generation += 1;
- // if let Some(e) = e {
- // result =
- // data.breakpoints
- // .insert(data.stack_depth, data.stack_generation, &e, result)
- // }
}
if let Err(mut err) = result {
err.trace_mut().0.push(StackTraceElement {
- location: e.cloned(),
+ location: Some(e.clone()),
desc: frame_desc(),
});
return Err(err);
}
result
}
+
/// Executes code creating a new stack frame
pub fn push_val(
&self,
- e: Option<&ExprLocation>,
+ e: &ExprLocation,
frame_desc: impl FnOnce() -> String,
f: impl FnOnce() -> Result<Val>,
) -> Result<Val> {
@@ -391,15 +394,45 @@
let mut data = self.data_mut();
data.stack_depth -= 1;
data.stack_generation += 1;
- if let Some(e) = e {
- result =
- data.breakpoints
- .insert(data.stack_depth, data.stack_generation, &e, result)
+ result = data
+ .breakpoints
+ .insert(data.stack_depth, data.stack_generation, &e, result);
+ }
+ if let Err(mut err) = result {
+ err.trace_mut().0.push(StackTraceElement {
+ location: Some(e.clone()),
+ desc: frame_desc(),
+ });
+ return Err(err);
+ }
+ result
+ }
+ /// Executes code creating a new stack frame
+ pub fn push_description<T>(
+ &self,
+ frame_desc: impl FnOnce() -> String,
+ f: impl FnOnce() -> Result<T>,
+ ) -> Result<T> {
+ {
+ let mut data = self.data_mut();
+ let stack_depth = &mut data.stack_depth;
+ if *stack_depth > self.max_stack() {
+ // Error creation uses data, so i drop guard here
+ drop(data);
+ throw!(StackOverflow);
+ } else {
+ *stack_depth += 1;
}
}
+ let result = f();
+ {
+ let mut data = self.data_mut();
+ data.stack_depth -= 1;
+ data.stack_generation += 1;
+ }
if let Err(mut err) = result {
err.trace_mut().0.push(StackTraceElement {
- location: e.cloned(),
+ location: None,
desc: frame_desc(),
});
return Err(err);
@@ -451,7 +484,12 @@
}
pub fn manifest(&self, val: Val) -> Result<IStr> {
- self.run_in_state(|| val.manifest(&self.manifest_format()))
+ self.run_in_state(|| {
+ push_description_frame(
+ || format!("manifestification"),
+ || val.manifest(&self.manifest_format()),
+ )
+ })
}
pub fn manifest_multi(&self, val: Val) -> Result<Vec<(IStr, IStr)>> {
self.run_in_state(|| val.manifest_multi(&self.manifest_format()))
@@ -464,8 +502,7 @@
pub fn with_tla(&self, val: Val) -> Result<Val> {
self.run_in_state(|| {
Ok(match val {
- Val::Func(func) => push_frame(
- None,
+ Val::Func(func) => push_description_frame(
|| "during TLA call".to_owned(),
|| {
func.evaluate_map(
@@ -511,7 +548,6 @@
&code,
&ParserSettings {
file_name: source.clone(),
- loc_data: true,
},
)
.map_err(|e| ImportSyntaxError {
@@ -570,7 +606,7 @@
self.settings_mut().import_resolver = resolver;
}
- pub fn add_native(&self, name: IStr, cb: Gc<NativeCallback>) {
+ pub fn add_native(&self, name: IStr, cb: Cc<NativeCallback>) {
self.settings_mut().ext_natives.insert(name, cb);
}
@@ -603,13 +639,20 @@
}
}
+pub fn cc_ptr_eq<T>(a: &Cc<T>, b: &Cc<T>) -> bool {
+ let a = &a as &T;
+ let b = &b as &T;
+ std::ptr::eq(a, b)
+}
+
#[cfg(test)]
pub mod tests {
use super::Val;
use crate::{
- error::Error::*, native::NativeCallbackHandler, primitive_equals, EvaluationState,
+ error::Error::*, gc::TraceBox, native::NativeCallbackHandler, primitive_equals,
+ EvaluationState,
};
- use jrsonnet_gc::{Finalize, Gc, Trace};
+ use gcmodule::{Cc, Trace};
use jrsonnet_interner::IStr;
use jrsonnet_parser::*;
use std::{
@@ -624,11 +667,11 @@
state.run_in_state(|| {
state
.push(
- Some(&ExprLocation(PathBuf::from("test1.jsonnet").into(), 10, 20)),
+ &ExprLocation(PathBuf::from("test1.jsonnet").into(), 10, 20),
|| "outer".to_owned(),
|| {
state.push(
- Some(&ExprLocation(PathBuf::from("test2.jsonnet").into(), 30, 40)),
+ &ExprLocation(PathBuf::from("test2.jsonnet").into(), 30, 40),
|| "inner".to_owned(),
|| Err(RuntimeError("".into()).into()),
)?;
@@ -1028,7 +1071,6 @@
"{ x: 1, y: 2 } == { x: 1, y: 2 }",
&ParserSettings {
file_name: PathBuf::from("equality").into(),
- loc_data: true,
}
)
);
@@ -1042,14 +1084,11 @@
evaluator.with_stdlib();
- #[derive(Trace, Finalize)]
+ #[derive(Trace)]
struct NativeAdd;
impl NativeCallbackHandler for NativeAdd {
- fn call(&self, from: Option<Rc<Path>>, args: &[Val]) -> crate::error::Result<Val> {
- assert_eq!(
- &from.unwrap() as &Path,
- &PathBuf::from("native_caller.jsonnet")
- );
+ fn call(&self, from: Rc<Path>, args: &[Val]) -> crate::error::Result<Val> {
+ assert_eq!(&from as &Path, &PathBuf::from("native_caller.jsonnet"));
match (&args[0], &args[1]) {
(Val::Num(a), Val::Num(b)) => Ok(Val::Num(a + b)),
(_, _) => unreachable!(),
@@ -1058,12 +1097,12 @@
}
evaluator.settings_mut().ext_natives.insert(
"native_add".into(),
- Gc::new(NativeCallback::new(
+ Cc::new(NativeCallback::new(
ParamsDesc(Rc::new(vec![
Param("a".into(), None),
Param("b".into(), None),
])),
- Box::new(NativeAdd),
+ TraceBox(Box::new(NativeAdd)),
)),
);
evaluator.evaluate_snippet_raw(
crates/jrsonnet-evaluator/src/map.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/map.rs
+++ b/crates/jrsonnet-evaluator/src/map.rs
@@ -1,23 +1,21 @@
-use jrsonnet_gc::{Gc, Trace};
+use gcmodule::{Cc, Trace};
use jrsonnet_interner::IStr;
-use rustc_hash::FxHashMap;
-use crate::LazyVal;
+use crate::{GcHashMap, LazyVal};
#[derive(Trace)]
-#[trivially_drop]
+#[force_tracking]
pub struct LayeredHashMapInternals {
parent: Option<LayeredHashMap>,
- current: FxHashMap<IStr, LazyVal>,
+ current: GcHashMap<IStr, LazyVal>,
}
#[derive(Trace)]
-#[trivially_drop]
-pub struct LayeredHashMap(Gc<LayeredHashMapInternals>);
+pub struct LayeredHashMap(Cc<LayeredHashMapInternals>);
impl LayeredHashMap {
- pub fn extend(self, new_layer: FxHashMap<IStr, LazyVal>) -> Self {
- Self(Gc::new(LayeredHashMapInternals {
+ pub fn extend(self, new_layer: GcHashMap<IStr, LazyVal>) -> Self {
+ Self(Cc::new(LayeredHashMapInternals {
parent: Some(self),
current: new_layer,
}))
@@ -49,9 +47,9 @@
impl Default for LayeredHashMap {
fn default() -> Self {
- Self(Gc::new(LayeredHashMapInternals {
+ Self(Cc::new(LayeredHashMapInternals {
parent: None,
- current: FxHashMap::default(),
+ current: GcHashMap::new(),
}))
}
}
crates/jrsonnet-evaluator/src/native.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/native.rs
+++ b/crates/jrsonnet-evaluator/src/native.rs
@@ -1,27 +1,27 @@
#![allow(clippy::type_complexity)]
+use crate::gc::TraceBox;
use crate::{error::Result, Val};
-use jrsonnet_gc::Trace;
+use gcmodule::Trace;
use jrsonnet_parser::ParamsDesc;
use std::fmt::Debug;
use std::path::Path;
use std::rc::Rc;
pub trait NativeCallbackHandler: Trace {
- fn call(&self, from: Option<Rc<Path>>, args: &[Val]) -> Result<Val>;
+ fn call(&self, from: Rc<Path>, args: &[Val]) -> Result<Val>;
}
#[derive(Trace)]
-#[trivially_drop]
pub struct NativeCallback {
pub params: ParamsDesc,
- handler: Box<dyn NativeCallbackHandler>,
+ handler: TraceBox<dyn NativeCallbackHandler>,
}
impl NativeCallback {
- pub fn new(params: ParamsDesc, handler: Box<dyn NativeCallbackHandler>) -> Self {
+ pub fn new(params: ParamsDesc, handler: TraceBox<dyn NativeCallbackHandler>) -> Self {
Self { params, handler }
}
- pub fn call(&self, caller: Option<Rc<Path>>, args: &[Val]) -> Result<Val> {
+ pub fn call(&self, caller: Rc<Path>, args: &[Val]) -> Result<Val> {
self.handler.call(caller, args)
}
}
crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/obj.rs
+++ b/crates/jrsonnet-evaluator/src/obj.rs
@@ -1,15 +1,15 @@
+use crate::gc::{GcHashMap, GcHashSet, TraceBox};
use crate::operator::evaluate_add_op;
-use crate::{Bindable, LazyBinding, LazyVal, Result, Val};
-use jrsonnet_gc::{Gc, GcCell, Trace};
+use crate::{cc_ptr_eq, Bindable, LazyBinding, LazyVal, Result, Val};
+use gcmodule::{Cc, Trace};
use jrsonnet_interner::IStr;
use jrsonnet_parser::{ExprLocation, Visibility};
-use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
-use std::collections::HashMap;
+use rustc_hash::FxHashMap;
+use std::cell::RefCell;
+use std::fmt::Debug;
use std::hash::{Hash, Hasher};
-use std::{fmt::Debug, hash::BuildHasherDefault};
#[derive(Debug, Trace)]
-#[trivially_drop]
pub struct ObjMember {
pub add: bool,
pub visibility: Visibility,
@@ -24,19 +24,18 @@
// Field => This
type CacheKey = (IStr, ObjValue);
#[derive(Trace)]
-#[trivially_drop]
+#[force_tracking]
pub struct ObjValueInternals {
super_obj: Option<ObjValue>,
- assertions: Gc<Vec<Box<dyn ObjectAssertion>>>,
- assertions_ran: GcCell<FxHashSet<ObjValue>>,
+ assertions: Cc<Vec<TraceBox<dyn ObjectAssertion>>>,
+ assertions_ran: RefCell<GcHashSet<ObjValue>>,
this_obj: Option<ObjValue>,
- this_entries: Gc<FxHashMap<IStr, ObjMember>>,
- value_cache: GcCell<FxHashMap<CacheKey, Option<Val>>>,
+ this_entries: Cc<GcHashMap<IStr, ObjMember>>,
+ value_cache: RefCell<GcHashMap<CacheKey, Option<Val>>>,
}
#[derive(Clone, Trace)]
-#[trivially_drop]
-pub struct ObjValue(pub(crate) Gc<ObjValueInternals>);
+pub struct ObjValue(pub(crate) Cc<ObjValueInternals>);
impl Debug for ObjValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(super_obj) = self.0.super_obj.as_ref() {
@@ -65,20 +64,20 @@
impl ObjValue {
pub fn new(
super_obj: Option<Self>,
- this_entries: Gc<FxHashMap<IStr, ObjMember>>,
- assertions: Gc<Vec<Box<dyn ObjectAssertion>>>,
+ this_entries: Cc<GcHashMap<IStr, ObjMember>>,
+ assertions: Cc<Vec<TraceBox<dyn ObjectAssertion>>>,
) -> Self {
- Self(Gc::new(ObjValueInternals {
+ Self(Cc::new(ObjValueInternals {
super_obj,
assertions,
- assertions_ran: GcCell::new(FxHashSet::default()),
+ assertions_ran: RefCell::new(GcHashSet::new()),
this_obj: None,
this_entries,
- value_cache: GcCell::new(FxHashMap::default()),
+ value_cache: RefCell::new(GcHashMap::new()),
}))
}
pub fn new_empty() -> Self {
- Self::new(None, Gc::new(FxHashMap::default()), Gc::new(Vec::new()))
+ Self::new(None, Cc::new(GcHashMap::new()), Cc::new(Vec::new()))
}
pub fn extend_from(&self, super_obj: Self) -> Self {
match &self.0.super_obj {
@@ -95,13 +94,13 @@
}
}
pub fn with_this(&self, this_obj: Self) -> Self {
- Self(Gc::new(ObjValueInternals {
+ Self(Cc::new(ObjValueInternals {
super_obj: self.0.super_obj.clone(),
assertions: self.0.assertions.clone(),
- assertions_ran: GcCell::new(FxHashSet::default()),
+ assertions_ran: RefCell::new(GcHashSet::new()),
this_obj: Some(this_obj),
this_entries: self.0.this_entries.clone(),
- value_cache: GcCell::new(FxHashMap::default()),
+ value_cache: RefCell::new(GcHashMap::new()),
}))
}
@@ -117,14 +116,14 @@
}
/// Run callback for every field found in object
- pub(crate) fn enum_fields(&self, handler: &mut impl FnMut(&IStr, &Visibility) -> bool) -> bool {
+ pub(crate) fn enum_fields(&self, handler: &mut impl FnMut(&IStr, &ObjMember) -> bool) -> bool {
if let Some(s) = &self.0.super_obj {
if s.enum_fields(handler) {
return true;
}
}
for (name, member) in self.0.this_entries.iter() {
- if handler(name, &member.visibility) {
+ if handler(name, &member) {
return true;
}
}
@@ -133,8 +132,8 @@
pub fn fields_visibility(&self) -> FxHashMap<IStr, bool> {
let mut out = FxHashMap::default();
- self.enum_fields(&mut |name, visibility| {
- match visibility {
+ self.enum_fields(&mut |name, member| {
+ match member.visibility {
Visibility::Normal => {
let entry = out.entry(name.to_owned());
entry.or_insert(true);
@@ -211,9 +210,9 @@
}
pub fn extend_with_field(self, key: IStr, value: ObjMember) -> Self {
- let mut new = FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());
+ let mut new = GcHashMap::with_capacity(1);
new.insert(key, value);
- Self::new(Some(self), Gc::new(new), Gc::new(Vec::new()))
+ Self::new(Some(self), Cc::new(new), Cc::new(Vec::new()))
}
fn get_raw(&self, key: IStr, real_this: Option<&Self>) -> Result<Option<Val>> {
@@ -270,13 +269,13 @@
}
pub fn ptr_eq(a: &Self, b: &Self) -> bool {
- Gc::ptr_eq(&a.0, &b.0)
+ cc_ptr_eq(&a.0, &b.0)
}
}
impl PartialEq for ObjValue {
fn eq(&self, other: &Self) -> bool {
- Gc::ptr_eq(&self.0, &other.0)
+ cc_ptr_eq(&self.0, &other.0)
}
}
@@ -289,8 +288,8 @@
pub struct ObjValueBuilder {
super_obj: Option<ObjValue>,
- map: FxHashMap<IStr, ObjMember>,
- assertions: Vec<Box<dyn ObjectAssertion>>,
+ map: GcHashMap<IStr, ObjMember>,
+ assertions: Vec<TraceBox<dyn ObjectAssertion>>,
}
impl ObjValueBuilder {
pub fn new() -> Self {
@@ -299,10 +298,7 @@
pub fn with_capacity(capacity: usize) -> Self {
Self {
super_obj: None,
- map: HashMap::with_capacity_and_hasher(
- capacity,
- BuildHasherDefault::<FxHasher>::default(),
- ),
+ map: GcHashMap::with_capacity(capacity),
assertions: Vec::new(),
}
}
@@ -315,7 +311,7 @@
self
}
- pub fn assert(&mut self, assertion: Box<dyn ObjectAssertion>) -> &mut Self {
+ pub fn assert(&mut self, assertion: TraceBox<dyn ObjectAssertion>) -> &mut Self {
self.assertions.push(assertion);
self
}
@@ -330,7 +326,7 @@
}
pub fn build(self) -> ObjValue {
- ObjValue::new(self.super_obj, Gc::new(self.map), Gc::new(self.assertions))
+ ObjValue::new(self.super_obj, Cc::new(self.map), Cc::new(self.assertions))
}
}
impl Default for ObjValueBuilder {
@@ -364,15 +360,15 @@
pub fn hide(self) -> Self {
self.with_visibility(Visibility::Hidden)
}
- pub fn with_location(mut self, location: Option<ExprLocation>) -> Self {
- self.location = location;
+ pub fn with_location(mut self, location: ExprLocation) -> Self {
+ self.location = Some(location);
self
}
pub fn value(self, value: Val) -> &'v mut ObjValueBuilder {
self.binding(LazyBinding::Bound(LazyVal::new_resolved(value)))
}
- pub fn bindable(self, bindable: Box<dyn Bindable>) -> &'v mut ObjValueBuilder {
- self.binding(LazyBinding::Bindable(Gc::new(bindable)))
+ pub fn bindable(self, bindable: TraceBox<dyn Bindable>) -> &'v mut ObjValueBuilder {
+ self.binding(LazyBinding::Bindable(Cc::new(bindable)))
}
pub fn binding(self, binding: LazyBinding) -> &'v mut ObjValueBuilder {
self.value.map.insert(
crates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/trace/mod.rs
+++ b/crates/jrsonnet-evaluator/src/trace/mod.rs
@@ -119,16 +119,21 @@
.trace()
.0
.iter()
- .map(|el| {
- el.location.as_ref().map(|l| {
- use std::fmt::Write;
- let mut resolved_path = self.resolver.resolve(&l.0);
+ .map(|el| &el.location)
+ .map(|location| {
+ use std::fmt::Write;
+ if let Some(location) = location {
+ let mut resolved_path = self.resolver.resolve(&location.0);
// TODO: Process all trace elements first
- let location = evaluation_state.map_source_locations(&l.0, &[l.1, l.2]);
+ let location = evaluation_state
+ .map_source_locations(&location.0, &[location.1, location.2]);
write!(resolved_path, ":").unwrap();
print_code_location(&mut resolved_path, &location[0], &location[1]).unwrap();
- resolved_path
- })
+ write!(resolved_path, ":").unwrap();
+ Some(resolved_path)
+ } else {
+ None
+ }
})
.collect::<Vec<_>>();
let align = file_names
@@ -139,15 +144,19 @@
.unwrap_or(0);
for (el, file) in error.trace().0.iter().zip(file_names) {
writeln!(out)?;
- write!(
- out,
- "{:<p$}{:<w$}: {}",
- "",
- file.unwrap_or_else(|| "".to_owned()),
- el.desc,
- p = self.padding,
- w = align
- )?;
+ if let Some(file) = file {
+ write!(
+ out,
+ "{:<p$}{:<w$} {}",
+ "",
+ file,
+ el.desc,
+ p = self.padding,
+ w = align
+ )?;
+ } else {
+ write!(out, "{:<p$}{}", "", el.desc, p = self.padding,)?;
+ }
}
Ok(())
}
@@ -178,7 +187,7 @@
start_end[0].column,
)?;
} else {
- write!(out, " at {}", desc,)?;
+ write!(out, " during {}", desc)?;
}
}
Ok(())
@@ -206,25 +215,21 @@
} = error.error()
{
writeln!(out)?;
- let mut offset = error.location.offset;
- if offset >= source_code.len() {
- offset = source_code.len() - 1;
- }
- let mut location = offset_to_location(source_code, &[offset])
+ let offset = error.location.offset;
+ let location = offset_to_location(source_code, &[offset])
.into_iter()
.next()
.unwrap();
- if location.column >= 1 {
- location.column -= 1;
- }
+ let mut end_location = location.clone();
+ end_location.offset += 1;
self.print_snippet(
out,
source_code,
path,
&location,
- &location,
- "^ syntax error",
+ &end_location,
+ "syntax error",
)?;
}
let trace = &error.trace();
@@ -289,7 +294,7 @@
annotation_type: AnnotationType::Error,
range: (
start.offset - start.line_start_offset,
- end.offset - start.line_start_offset,
+ (end.offset - start.line_start_offset).min(source_fragment.len()),
),
}],
}],
crates/jrsonnet-evaluator/src/typed.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/typed.rs
+++ b/crates/jrsonnet-evaluator/src/typed.rs
@@ -1,11 +1,7 @@
use std::{fmt::Display, rc::Rc};
-use crate::{
- error::{Error, LocError, Result},
- push_frame, Val,
-};
-use jrsonnet_gc::Trace;
-use jrsonnet_parser::ExprLocation;
+use crate::{Val, error::{Error, LocError, Result}, push_description_frame};
+use gcmodule::Trace;
use jrsonnet_types::{ComplexValType, ValType};
use thiserror::Error;
@@ -22,12 +18,11 @@
}
#[derive(Debug, Error, Clone, Trace)]
-#[trivially_drop]
pub enum TypeError {
#[error("expected {0}, got {1}")]
ExpectedGot(ComplexValType, ValType),
#[error("missing property {0} from {1:?}")]
- MissingProperty(Rc<str>, ComplexValType),
+ MissingProperty(#[skip_trace] Rc<str>, ComplexValType),
#[error("every failed from {0}:\n{1}")]
UnionFailed(ComplexValType, TypeLocErrorList),
#[error(
@@ -44,7 +39,6 @@
}
#[derive(Debug, Clone, Trace)]
-#[trivially_drop]
pub struct TypeLocError(Box<TypeError>, ValuePathStack);
impl From<TypeError> for TypeLocError {
fn from(e: TypeError) -> Self {
@@ -67,7 +61,6 @@
}
#[derive(Debug, Clone, Trace)]
-#[trivially_drop]
pub struct TypeLocErrorList(Vec<TypeLocError>);
impl Display for TypeLocErrorList {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -97,13 +90,12 @@
}
}
-fn push_type(
- location: Option<&ExprLocation>,
+fn push_type_description(
error_reason: impl Fn() -> String,
path: impl Fn() -> ValuePathItem,
item: impl Fn() -> Result<()>,
) -> Result<()> {
- push_frame(location, error_reason, || match item() {
+ push_description_frame(error_reason, || match item() {
Ok(_) => Ok(()),
Err(mut e) => {
if let Error::TypeError(e) = &mut e.error_mut() {
@@ -131,9 +123,8 @@
}
#[derive(Clone, Debug, Trace)]
-#[trivially_drop]
enum ValuePathItem {
- Field(Rc<str>),
+ Field(#[skip_trace] Rc<str>),
Index(u64),
}
impl Display for ValuePathItem {
@@ -147,7 +138,6 @@
}
#[derive(Clone, Debug, Trace)]
-#[trivially_drop]
struct ValuePathStack(Vec<ValuePathItem>);
impl Display for ValuePathStack {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -183,8 +173,7 @@
Self::Array(elem_type) => match value {
Val::Arr(a) => {
for (i, item) in a.iter().enumerate() {
- push_type(
- None,
+ push_type_description(
|| format!("array index {}", i),
|| ValuePathItem::Index(i as u64),
|| elem_type.check(&item.clone()?),
@@ -197,8 +186,7 @@
Self::ArrayRef(elem_type) => match value {
Val::Arr(a) => {
for (i, item) in a.iter().enumerate() {
- push_type(
- None,
+ push_type_description(
|| format!("array index {}", i),
|| ValuePathItem::Index(i as u64),
|| elem_type.check(&item.clone()?),
@@ -212,8 +200,7 @@
Val::Obj(obj) => {
for (k, v) in elems.iter() {
if let Some(got_v) = obj.get((*k).into())? {
- push_type(
- None,
+ push_type_description(
|| format!("property {}", k),
|| ValuePathItem::Field((*k).into()),
|| v.check(&got_v),
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -6,40 +6,40 @@
ManifestYamlOptions,
},
},
+ cc_ptr_eq,
error::{Error::*, LocError},
evaluate,
function::{parse_function_call, parse_function_call_map, place_args},
+ gc::TraceBox,
native::NativeCallback,
throw, Context, ObjValue, Result,
};
-use jrsonnet_gc::{Gc, GcCell, Trace};
+use gcmodule::{Cc, Trace};
use jrsonnet_interner::IStr;
use jrsonnet_parser::{ArgsDesc, ExprLocation, LocExpr, ParamsDesc};
use jrsonnet_types::ValType;
-use std::{collections::HashMap, fmt::Debug, rc::Rc};
+use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
pub trait LazyValValue: Trace {
fn get(self: Box<Self>) -> Result<Val>;
}
#[derive(Trace)]
-#[trivially_drop]
enum LazyValInternals {
Computed(Val),
Errored(LocError),
- Waiting(Box<dyn LazyValValue>),
+ Waiting(TraceBox<dyn LazyValValue>),
Pending,
}
#[derive(Clone, Trace)]
-#[trivially_drop]
-pub struct LazyVal(Gc<GcCell<LazyValInternals>>);
+pub struct LazyVal(Cc<RefCell<LazyValInternals>>);
impl LazyVal {
- pub fn new(f: Box<dyn LazyValValue>) -> Self {
- Self(Gc::new(GcCell::new(LazyValInternals::Waiting(f))))
+ pub fn new(f: TraceBox<dyn LazyValValue>) -> Self {
+ Self(Cc::new(RefCell::new(LazyValInternals::Waiting(f))))
}
pub fn new_resolved(val: Val) -> Self {
- Self(Gc::new(GcCell::new(LazyValInternals::Computed(val))))
+ Self(Cc::new(RefCell::new(LazyValInternals::Computed(val))))
}
pub fn evaluate(&self) -> Result<Val> {
match &*self.0.borrow() {
@@ -55,7 +55,7 @@
} else {
unreachable!()
};
- let new_value = match value.get() {
+ let new_value = match value.0.get() {
Ok(v) => v,
Err(e) => {
*self.0.borrow_mut() = LazyValInternals::Errored(e.clone());
@@ -74,12 +74,11 @@
}
impl PartialEq for LazyVal {
fn eq(&self, other: &Self) -> bool {
- Gc::ptr_eq(&self.0, &other.0)
+ cc_ptr_eq(&self.0, &other.0)
}
}
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub struct FuncDesc {
pub name: IStr,
pub ctx: Context,
@@ -88,14 +87,13 @@
}
#[derive(Debug, Trace)]
-#[trivially_drop]
pub enum FuncVal {
/// Plain function implemented in jsonnet
Normal(FuncDesc),
/// Standard library function
Intrinsic(IStr),
/// Library functions implemented in native
- NativeExt(IStr, Gc<NativeCallback>),
+ NativeExt(IStr, Cc<NativeCallback>),
}
impl PartialEq for FuncVal {
@@ -122,7 +120,7 @@
pub fn evaluate(
&self,
call_ctx: Context,
- loc: Option<&ExprLocation>,
+ loc: &ExprLocation,
args: &ArgsDesc,
tailstrict: bool,
) -> Result<Val> {
@@ -145,7 +143,7 @@
for p in handler.params.0.iter() {
out_args.push(args.binding(p.0.clone())?.evaluate()?);
}
- Ok(handler.call(loc.map(|l| l.0.clone()), &out_args)?)
+ Ok(handler.call(loc.0.clone(), &out_args)?)
}
}
}
@@ -194,15 +192,15 @@
}
#[derive(Debug, Clone, Trace)]
-#[trivially_drop]
+#[force_tracking]
pub enum ArrValue {
- Lazy(Gc<Vec<LazyVal>>),
- Eager(Gc<Vec<Val>>),
+ Lazy(Cc<Vec<LazyVal>>),
+ Eager(Cc<Vec<Val>>),
Extended(Box<(Self, Self)>),
}
impl ArrValue {
pub fn new_eager() -> Self {
- Self::Eager(Gc::new(Vec::new()))
+ Self::Eager(Cc::new(Vec::new()))
}
pub fn len(&self) -> usize {
@@ -253,14 +251,14 @@
}
}
- pub fn evaluated(&self) -> Result<Gc<Vec<Val>>> {
+ pub fn evaluated(&self) -> Result<Cc<Vec<Val>>> {
Ok(match self {
Self::Lazy(vec) => {
let mut out = Vec::with_capacity(vec.len());
for item in vec.iter() {
out.push(item.evaluate()?);
}
- Gc::new(out)
+ Cc::new(out)
}
Self::Eager(vec) => vec.clone(),
Self::Extended(_v) => {
@@ -268,7 +266,7 @@
for item in self.iter() {
out.push(item?);
}
- Gc::new(out)
+ Cc::new(out)
}
})
}
@@ -294,12 +292,12 @@
Self::Lazy(vec) => {
let mut out = (&vec as &Vec<_>).clone();
out.reverse();
- Self::Lazy(Gc::new(out))
+ Self::Lazy(Cc::new(out))
}
Self::Eager(vec) => {
let mut out = (&vec as &Vec<_>).clone();
out.reverse();
- Self::Eager(Gc::new(out))
+ Self::Eager(Cc::new(out))
}
Self::Extended(b) => Self::Extended(Box::new((b.1.reversed(), b.0.reversed()))),
}
@@ -312,7 +310,7 @@
out.push(mapper(value?)?);
}
- Ok(Self::Eager(Gc::new(out)))
+ Ok(Self::Eager(Cc::new(out)))
}
pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {
@@ -325,13 +323,13 @@
}
}
- Ok(Self::Eager(Gc::new(out)))
+ Ok(Self::Eager(Cc::new(out)))
}
pub fn ptr_eq(a: &Self, b: &Self) -> bool {
match (a, b) {
- (Self::Lazy(a), Self::Lazy(b)) => Gc::ptr_eq(a, b),
- (Self::Eager(a), Self::Eager(b)) => Gc::ptr_eq(a, b),
+ (Self::Lazy(a), Self::Lazy(b)) => cc_ptr_eq(a, b),
+ (Self::Eager(a), Self::Eager(b)) => cc_ptr_eq(a, b),
_ => false,
}
}
@@ -339,13 +337,13 @@
impl From<Vec<LazyVal>> for ArrValue {
fn from(v: Vec<LazyVal>) -> Self {
- Self::Lazy(Gc::new(v))
+ Self::Lazy(Cc::new(v))
}
}
impl From<Vec<Val>> for ArrValue {
fn from(v: Vec<Val>) -> Self {
- Self::Eager(Gc::new(v))
+ Self::Eager(Cc::new(v))
}
}
@@ -355,7 +353,6 @@
}
#[derive(Debug, Clone, Trace)]
-#[trivially_drop]
pub enum Val {
Bool(bool),
Null,
@@ -363,7 +360,7 @@
Num(f64),
Arr(ArrValue),
Obj(ObjValue),
- Func(Gc<FuncVal>),
+ Func(Cc<FuncVal>),
}
macro_rules! matches_unwrap {
@@ -402,7 +399,7 @@
pub fn unwrap_arr(self) -> Result<ArrValue> {
Ok(matches_unwrap!(self, Self::Arr(v), v))
}
- pub fn unwrap_func(self) -> Result<Gc<FuncVal>> {
+ pub fn unwrap_func(self) -> Result<Cc<FuncVal>> {
Ok(matches_unwrap!(self, Self::Func(v), v))
}
pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {
crates/jrsonnet-interner/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-interner/Cargo.toml
+++ b/crates/jrsonnet-interner/Cargo.toml
@@ -9,4 +9,4 @@
[dependencies]
serde = { version = "1.0" }
rustc-hash = "1.1.0"
-jrsonnet-gc = { version = "0.4.2", features = ["derive"] }
+gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" }
crates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-interner/src/lib.rs
+++ b/crates/jrsonnet-interner/src/lib.rs
@@ -1,4 +1,4 @@
-use jrsonnet_gc::{unsafe_empty_trace, Finalize, Trace};
+use gcmodule::Trace;
use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
use std::{
@@ -11,9 +11,10 @@
#[derive(Clone, PartialOrd, Ord, Eq)]
pub struct IStr(Rc<str>);
-impl Finalize for IStr {}
-unsafe impl Trace for IStr {
- unsafe_empty_trace!();
+impl Trace for IStr {
+ fn is_type_tracked() -> bool {
+ false
+ }
}
impl Deref for IStr {
crates/jrsonnet-parser/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-parser/Cargo.toml
+++ b/crates/jrsonnet-parser/Cargo.toml
@@ -15,10 +15,9 @@
jrsonnet-interner = { path = "../jrsonnet-interner", version = "0.4.2" }
peg = "0.7.0"
-unescape = "0.1.0"
serde = { version = "1.0", features = ["derive", "rc"], optional = true }
-jrsonnet-gc = { version = "0.4.2", features = ["derive"] }
+gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" }
[dev-dependencies]
jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.4.2" }
crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/expr.rs
+++ b/crates/jrsonnet-parser/src/expr.rs
@@ -1,4 +1,4 @@
-use jrsonnet_gc::{unsafe_empty_trace, Finalize, Trace};
+use gcmodule::Trace;
use jrsonnet_interner::IStr;
#[cfg(feature = "deserialize")]
use serde::Deserialize;
@@ -14,7 +14,6 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub enum FieldName {
/// {fixed: 2}
Fixed(IStr),
@@ -25,7 +24,6 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Trace)]
-#[trivially_drop]
pub enum Visibility {
/// :
Normal,
@@ -44,13 +42,11 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Clone, Debug, PartialEq, Trace)]
-#[trivially_drop]
pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub struct FieldMember {
pub name: FieldName,
pub plus: bool,
@@ -62,7 +58,6 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub enum Member {
Field(FieldMember),
BindStmt(BindSpec),
@@ -72,7 +67,6 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Trace)]
-#[trivially_drop]
pub enum UnaryOpType {
Plus,
Minus,
@@ -99,7 +93,6 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Trace)]
-#[trivially_drop]
pub enum BinaryOpType {
Mul,
Div,
@@ -167,21 +160,13 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub struct Param(pub IStr, pub Option<LocExpr>);
/// Defined function parameters
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Trace)]
pub struct ParamsDesc(pub Rc<Vec<Param>>);
-
-/// Safety:
-/// AST is acyclic, and there should be no gc pointers
-unsafe impl Trace for ParamsDesc {
- unsafe_empty_trace!();
-}
-impl Finalize for ParamsDesc {}
impl Deref for ParamsDesc {
type Target = Vec<Param>;
@@ -193,7 +178,6 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub struct ArgsDesc {
pub unnamed: Vec<LocExpr>,
pub named: Vec<(IStr, LocExpr)>,
@@ -207,7 +191,6 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, Clone, PartialEq, Trace)]
-#[trivially_drop]
pub struct BindSpec {
pub name: IStr,
pub params: Option<ParamsDesc>,
@@ -217,19 +200,16 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub struct IfSpecData(pub LocExpr);
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub struct ForSpecData(pub IStr, pub LocExpr);
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub enum CompSpec {
IfSpec(IfSpecData),
ForSpec(ForSpecData),
@@ -238,7 +218,6 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub struct ObjComp {
pub pre_locals: Vec<BindSpec>,
pub key: LocExpr,
@@ -251,7 +230,6 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub enum ObjBody {
MemberList(Vec<Member>),
ObjComp(ObjComp),
@@ -260,7 +238,6 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Clone, Copy, Trace)]
-#[trivially_drop]
pub enum LiteralType {
This,
Super,
@@ -273,7 +250,6 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub struct SliceDesc {
pub start: Option<LocExpr>,
pub end: Option<LocExpr>,
@@ -284,7 +260,6 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Debug, PartialEq, Trace)]
-#[trivially_drop]
pub enum Expr {
Literal(LiteralType),
@@ -354,7 +329,7 @@
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[derive(Clone, PartialEq, Trace)]
-#[trivially_drop]
+#[skip_trace]
pub struct ExprLocation(pub Rc<Path>, pub usize, pub usize);
impl ExprLocation {
pub fn belongs_to(&self, other: &ExprLocation) -> bool {
@@ -371,14 +346,8 @@
/// Holds AST expression and its location in source file
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
-#[derive(Clone, PartialEq)]
-pub struct LocExpr(pub Rc<Expr>, pub Option<ExprLocation>);
-/// Safety:
-/// AST is acyclic, and there should be no gc pointers
-unsafe impl Trace for LocExpr {
- unsafe_empty_trace!();
-}
-impl Finalize for LocExpr {}
+#[derive(Clone, PartialEq, Trace)]
+pub struct LocExpr(pub Rc<Expr>, pub ExprLocation);
impl Debug for LocExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -387,24 +356,7 @@
} else {
write!(f, "{:?}", self.0)?;
}
- if let Some(loc) = &self.1 {
- write!(f, " from {:?}", loc)?;
- }
+ write!(f, " from {:?}", self.1)?;
Ok(())
}
-}
-
-/// Creates LocExpr from Expr and ExprLocation components
-#[macro_export]
-macro_rules! loc_expr {
- ($expr:expr, $need_loc:expr,($name:expr, $start:expr, $end:expr)) => {
- LocExpr(
- std::rc::Rc::new($expr),
- if $need_loc {
- Some(ExprLocation($name, $start, $end))
- } else {
- None
- },
- )
- };
}
crates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth1#![allow(clippy::redundant_closure_call)]23use peg::parser;4use std::{5 path::{Path, PathBuf},6 rc::Rc,7};8mod expr;9pub use expr::*;10pub use jrsonnet_interner::IStr;11pub use peg;1213pub struct ParserSettings {14 pub loc_data: bool,15 pub file_name: Rc<Path>,16}1718macro_rules! expr_bin {19 ($a:ident $op:ident $b:ident) => {20 Expr::BinaryOp($a, $op, $b)21 };22}23macro_rules! expr_un {24 ($op:ident $a:ident) => {25 Expr::UnaryOp($op, $a)26 };27}2829parser! {30 grammar jsonnet_parser() for str {31 use peg::ParseLiteral;3233 rule eof() = quiet!{![_]} / expected!("<eof>")34 rule eol() = "\n" / eof()3536 /// Standard C-like comments37 rule comment()38 = "//" (!eol()[_])* eol()39 / "/*" ("\\*/" / "\\\\" / (!("*/")[_]))* "*/"40 / "#" (!eol()[_])* eol()4142 rule single_whitespace() = quiet!{([' ' | '\r' | '\n' | '\t'] / comment())} / expected!("<whitespace>")43 rule _() = single_whitespace()*4445 /// For comma-delimited elements46 rule comma() = quiet!{_ "," _} / expected!("<comma>")47 rule alpha() -> char = c:$(['_' | 'a'..='z' | 'A'..='Z']) {c.chars().next().unwrap()}48 rule digit() -> char = d:$(['0'..='9']) {d.chars().next().unwrap()}49 rule end_of_ident() = !['0'..='9' | '_' | 'a'..='z' | 'A'..='Z']50 /// Sequence of digits51 rule uint_str() -> &'input str = a:$(digit()+) { a }52 /// Number in scientific notation format53 rule number() -> f64 = quiet!{a:$(uint_str() ("." uint_str())? (['e'|'E'] (s:['+'|'-'])? uint_str())?) {? a.parse().map_err(|_| "<number>") }} / expected!("<number>")5455 /// Reserved word followed by any non-alphanumberic56 rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()57 rule id() = quiet!{ !reserved() alpha() (alpha() / digit())*} / expected!("<identifier>")5859 rule keyword(id: &'static str) -> ()60 = ##parse_string_literal(id) end_of_ident()6162 pub rule param(s: &ParserSettings) -> expr::Param = name:$(id()) expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name.into(), expr) }63 pub rule params(s: &ParserSettings) -> expr::ParamsDesc64 = params:param(s) ** comma() comma()? { expr::ParamsDesc(Rc::new(params)) }65 / { expr::ParamsDesc(Rc::new(Vec::new())) }6667 pub rule arg(s: &ParserSettings) -> (Option<IStr>, LocExpr)68 = quiet! { name:(s:$(id()) _ "=" _ {s})? expr:expr(s) {(name.map(Into::into), expr)} }69 / expected!("<argument>")7071 pub rule args(s: &ParserSettings) -> expr::ArgsDesc72 = args:arg(s)**comma() comma()? {?73 let unnamed_count = args.iter().take_while(|(n, _)| n.is_none()).count();74 let mut unnamed = Vec::with_capacity(unnamed_count);75 let mut named = Vec::with_capacity(args.len() - unnamed_count);76 let mut named_started = false;77 for (name, value) in args {78 if let Some(name) = name {79 named_started = true;80 named.push((name, value));81 } else {82 if named_started {83 return Err("<named argument>")84 }85 unnamed.push(value);86 }87 }88 Ok(expr::ArgsDesc::new(unnamed, named))89 }9091 pub rule bind(s: &ParserSettings) -> expr::BindSpec92 = name:$(id()) _ "=" _ expr:expr(s) {expr::BindSpec{name:name.into(), params: None, value: expr}}93 / name:$(id()) _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec{name:name.into(), params: Some(params), value: expr}}94 pub rule assertion(s: &ParserSettings) -> expr::AssertStmt95 = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) }9697 pub rule whole_line() -> &'input str98 = str:$((!['\n'][_])* "\n") {str}99 pub rule string_block() -> String100 = "|||" (!['\n']single_whitespace())* "\n"101 empty_lines:$(['\n']*)102 prefix:[' ' | '\t']+ first_line:whole_line()103 lines:("\n" {"\n"} / [' ' | '\t']*<{prefix.len()}> s:whole_line() {s})*104 [' ' | '\t']*<, {prefix.len() - 1}> "|||"105 {let mut l = empty_lines.to_owned(); l.push_str(first_line); l.extend(lines); l}106 pub rule string() -> String107 = quiet!{ "\"" str:$(("\\\"" / "\\\\" / (!['"'][_]))*) "\"" {unescape::unescape(str).unwrap()}108 / "'" str:$(("\\'" / "\\\\" / (!['\''][_]))*) "'" {unescape::unescape(str).unwrap()}109 / "@'" str:$(("''" / (!['\''][_]))*) "'" {str.replace("''", "'")}110 / "@\"" str:$(("\"\"" / (!['"'][_]))*) "\"" {str.replace("\"\"", "\"")}111 / string_block() } / expected!("<string>")112113 pub rule field_name(s: &ParserSettings) -> expr::FieldName114 = name:$(id()) {expr::FieldName::Fixed(name.into())}115 / name:string() {expr::FieldName::Fixed(name.into())}116 / "[" _ expr:expr(s) _ "]" {expr::FieldName::Dyn(expr)}117 pub rule visibility() -> expr::Visibility118 = ":::" {expr::Visibility::Unhide}119 / "::" {expr::Visibility::Hidden}120 / ":" {expr::Visibility::Normal}121 pub rule field(s: &ParserSettings) -> expr::FieldMember122 = name:field_name(s) _ plus:"+"? _ visibility:visibility() _ value:expr(s) {expr::FieldMember{123 name,124 plus: plus.is_some(),125 params: None,126 visibility,127 value,128 }}129 / name:field_name(s) _ "(" _ params:params(s) _ ")" _ visibility:visibility() _ value:expr(s) {expr::FieldMember{130 name,131 plus: false,132 params: Some(params),133 visibility,134 value,135 }}136 pub rule obj_local(s: &ParserSettings) -> BindSpec137 = keyword("local") _ bind:bind(s) {bind}138 pub rule member(s: &ParserSettings) -> expr::Member139 = bind:obj_local(s) {expr::Member::BindStmt(bind)}140 / assertion:assertion(s) {expr::Member::AssertStmt(assertion)}141 / field:field(s) {expr::Member::Field(field)}142 pub rule objinside(s: &ParserSettings) -> expr::ObjBody143 = pre_locals:(b: obj_local(s) comma() {b})* "[" _ key:expr(s) _ "]" _ plus:"+"? _ ":" _ value:expr(s) post_locals:(comma() b:obj_local(s) {b})* _ forspec:forspec(s) others:(_ rest:compspec(s) {rest})? {144 let mut compspecs = vec![CompSpec::ForSpec(forspec)];145 compspecs.extend(others.unwrap_or_default());146 expr::ObjBody::ObjComp(expr::ObjComp{147 pre_locals,148 key,149 plus: plus.is_some(),150 value,151 post_locals,152 compspecs,153 })154 }155 / members:(member(s) ** comma()) comma()? {expr::ObjBody::MemberList(members)}156 pub rule ifspec(s: &ParserSettings) -> IfSpecData157 = keyword("if") _ expr:expr(s) {IfSpecData(expr)}158 pub rule forspec(s: &ParserSettings) -> ForSpecData159 = keyword("for") _ id:$(id()) _ keyword("in") _ cond:expr(s) {ForSpecData(id.into(), cond)}160 pub rule compspec(s: &ParserSettings) -> Vec<expr::CompSpec>161 = s:(i:ifspec(s) { expr::CompSpec::IfSpec(i) } / f:forspec(s) {expr::CompSpec::ForSpec(f)} ) ** _ {s}162 pub rule local_expr(s: &ParserSettings) -> Expr163 = keyword("local") _ binds:bind(s) ** comma() _ ";" _ expr:expr(s) { Expr::LocalExpr(binds, expr) }164 pub rule string_expr(s: &ParserSettings) -> Expr165 = s:string() {Expr::Str(s.into())}166 pub rule obj_expr(s: &ParserSettings) -> Expr167 = "{" _ body:objinside(s) _ "}" {Expr::Obj(body)}168 pub rule array_expr(s: &ParserSettings) -> Expr169 = "[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(elems)}170 pub rule array_comp_expr(s: &ParserSettings) -> Expr171 = "[" _ expr:expr(s) _ comma()? _ forspec:forspec(s) _ others:(others: compspec(s) _ {others})? "]" {172 let mut specs = vec![CompSpec::ForSpec(forspec)];173 specs.extend(others.unwrap_or_default());174 Expr::ArrComp(expr, specs)175 }176 pub rule number_expr(s: &ParserSettings) -> Expr177 = n:number() { expr::Expr::Num(n) }178 pub rule var_expr(s: &ParserSettings) -> Expr179 = n:$(id()) { expr::Expr::Var(n.into()) }180 pub rule if_then_else_expr(s: &ParserSettings) -> Expr181 = cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse{182 cond,183 cond_then,184 cond_else,185 }}186187 pub rule literal(s: &ParserSettings) -> Expr188 = v:(189 keyword("null") {LiteralType::Null}190 / keyword("true") {LiteralType::True}191 / keyword("false") {LiteralType::False}192 / keyword("self") {LiteralType::This}193 / keyword("$") {LiteralType::Dollar}194 / keyword("super") {LiteralType::Super}195 ) {Expr::Literal(v)}196197 pub rule expr_basic(s: &ParserSettings) -> Expr198 = literal(s)199200 / quiet!{"$intrinsic(" name:$(id()) ")" {Expr::Intrinsic(name.into())}}201202 / string_expr(s) / number_expr(s)203 / array_expr(s)204 / obj_expr(s)205 / array_expr(s)206 / array_comp_expr(s)207208 / keyword("importstr") _ path:string() {Expr::ImportStr(PathBuf::from(path))}209 / keyword("import") _ path:string() {Expr::Import(PathBuf::from(path))}210211 / var_expr(s)212 / local_expr(s)213 / if_then_else_expr(s)214215 / keyword("function") _ "(" _ params:params(s) _ ")" _ expr:expr(s) {Expr::Function(params, expr)}216 / assertion:assertion(s) _ ";" _ expr:expr(s) { Expr::AssertExpr(assertion, expr) }217218 / keyword("error") _ expr:expr(s) { Expr::ErrorStmt(expr) }219220 rule slice_part(s: &ParserSettings) -> Option<LocExpr>221 = e:(_ e:expr(s) _{e})? {e}222 pub rule slice_desc(s: &ParserSettings) -> SliceDesc223 = start:slice_part(s) ":" pair:(end:slice_part(s) step:(":" e:slice_part(s){e})? {(end, step.flatten())})? {224 let (end, step) = if let Some((end, step)) = pair {225 (end, step)226 }else{227 (None, None)228 };229230 SliceDesc { start, end, step }231 }232233 rule binop(x: rule<()>) -> ()234 = quiet!{ x() } / expected!("<binary op>")235 rule unaryop(x: rule<()>) -> ()236 = quiet!{ x() } / expected!("<unary op>")237238239 use BinaryOpType::*;240 use UnaryOpType::*;241 rule expr(s: &ParserSettings) -> LocExpr242 = precedence! {243 start:position!() v:@ end:position!() { loc_expr!(v, s.loc_data, (s.file_name.clone(), start, end)) }244 --245 a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)}246 --247 a:(@) _ binop(<"&&">) _ b:@ {expr_bin!(a And b)}248 --249 a:(@) _ binop(<"|">) _ b:@ {expr_bin!(a BitOr b)}250 --251 a:@ _ binop(<"^">) _ b:(@) {expr_bin!(a BitXor b)}252 --253 a:(@) _ binop(<"&">) _ b:@ {expr_bin!(a BitAnd b)}254 --255 a:(@) _ binop(<"==">) _ b:@ {expr_bin!(a Eq b)}256 a:(@) _ binop(<"!=">) _ b:@ {expr_bin!(a Neq b)}257 --258 a:(@) _ binop(<"<">) _ b:@ {expr_bin!(a Lt b)}259 a:(@) _ binop(<">">) _ b:@ {expr_bin!(a Gt b)}260 a:(@) _ binop(<"<=">) _ b:@ {expr_bin!(a Lte b)}261 a:(@) _ binop(<">=">) _ b:@ {expr_bin!(a Gte b)}262 a:(@) _ binop(<keyword("in")>) _ b:@ {expr_bin!(a In b)}263 --264 a:(@) _ binop(<"<<">) _ b:@ {expr_bin!(a Lhs b)}265 a:(@) _ binop(<">>">) _ b:@ {expr_bin!(a Rhs b)}266 --267 a:(@) _ binop(<"+">) _ b:@ {expr_bin!(a Add b)}268 a:(@) _ binop(<"-">) _ b:@ {expr_bin!(a Sub b)}269 --270 a:(@) _ binop(<"*">) _ b:@ {expr_bin!(a Mul b)}271 a:(@) _ binop(<"/">) _ b:@ {expr_bin!(a Div b)}272 a:(@) _ binop(<"%">) _ b:@ {expr_bin!(a Mod b)}273 --274 unaryop(<"-">) _ b:@ {expr_un!(Minus b)}275 unaryop(<"!">) _ b:@ {expr_un!(Not b)}276 unaryop(<"~">) _ b:@ {expr_un!(BitNot b)}277 --278 a:(@) _ "[" _ e:slice_desc(s) _ "]" {Expr::Slice(a, e)}279 a:(@) _ "." _ e:$(id()) {Expr::Index(a, el!(Expr::Str(e.into())))}280 a:(@) _ "[" _ e:expr(s) _ "]" {Expr::Index(a, e)}281 a:(@) _ "(" _ args:args(s) _ ")" ts:(_ keyword("tailstrict"))? {Expr::Apply(a, args, ts.is_some())}282 a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(a, body)}283 --284 e:expr_basic(s) {e}285 "(" _ e:expr(s) _ ")" {Expr::Parened(e)}286 }287288 pub rule jsonnet(s: &ParserSettings) -> LocExpr = _ e:expr(s) _ {e}289 }290}291292pub type ParseError = peg::error::ParseError<peg::str::LineCol>;293pub fn parse(str: &str, settings: &ParserSettings) -> Result<LocExpr, ParseError> {294 jsonnet_parser::jsonnet(str, settings)295}296297#[macro_export]298macro_rules! el {299 ($expr:expr) => {300 LocExpr(std::rc::Rc::new($expr), None)301 };302}303304#[cfg(test)]305pub mod tests {306 use super::{expr::*, parse};307 use crate::ParserSettings;308 use std::path::PathBuf;309 use BinaryOpType::*;310311 macro_rules! parse {312 ($s:expr) => {313 parse(314 $s,315 &ParserSettings {316 loc_data: false,317 file_name: PathBuf::from("/test.jsonnet").into(),318 },319 )320 .unwrap()321 };322 }323324 macro_rules! el_loc {325 ($expr:expr, $loc:expr$(,)?) => {326 LocExpr(std::rc::Rc::new($expr), Some($loc))327 };328 }329330 mod expressions {331 use super::*;332333 pub fn basic_math() -> LocExpr {334 el!(Expr::BinaryOp(335 el!(Expr::Num(2.0)),336 Add,337 el!(Expr::BinaryOp(338 el!(Expr::Num(2.0)),339 Mul,340 el!(Expr::Num(2.0)),341 )),342 ))343 }344 }345346 #[test]347 fn multiline_string() {348 assert_eq!(349 parse!("|||\n Hello world!\n a\n|||"),350 el!(Expr::Str("Hello world!\n a\n".into())),351 );352 assert_eq!(353 parse!("|||\n Hello world!\n a\n|||"),354 el!(Expr::Str("Hello world!\n a\n".into())),355 );356 assert_eq!(357 parse!("|||\n\t\tHello world!\n\t\t\ta\n|||"),358 el!(Expr::Str("Hello world!\n\ta\n".into())),359 );360 assert_eq!(361 parse!("|||\n Hello world!\n a\n |||"),362 el!(Expr::Str("Hello world!\n a\n".into())),363 );364 }365366 #[test]367 fn slice() {368 parse!("a[1:]");369 parse!("a[1::]");370 parse!("a[:1:]");371 parse!("a[::1]");372 parse!("str[:len - 1]");373 }374375 #[test]376 fn string_escaping() {377 assert_eq!(378 parse!(r#""Hello, \"world\"!""#),379 el!(Expr::Str(r#"Hello, "world"!"#.into())),380 );381 assert_eq!(382 parse!(r#"'Hello \'world\'!'"#),383 el!(Expr::Str("Hello 'world'!".into())),384 );385 assert_eq!(parse!(r#"'\\\\'"#), el!(Expr::Str("\\\\".into())),);386 }387388 #[test]389 fn string_unescaping() {390 assert_eq!(391 parse!(r#""Hello\nWorld""#),392 el!(Expr::Str("Hello\nWorld".into())),393 );394 }395396 #[test]397 fn string_verbantim() {398 assert_eq!(399 parse!(r#"@"Hello\n""World""""#),400 el!(Expr::Str("Hello\\n\"World\"".into())),401 );402 }403404 #[test]405 fn imports() {406 assert_eq!(407 parse!("import \"hello\""),408 el!(Expr::Import(PathBuf::from("hello"))),409 );410 assert_eq!(411 parse!("importstr \"garnish.txt\""),412 el!(Expr::ImportStr(PathBuf::from("garnish.txt")))413 );414 }415416 #[test]417 fn empty_object() {418 assert_eq!(parse!("{}"), el!(Expr::Obj(ObjBody::MemberList(vec![]))));419 }420421 #[test]422 fn basic_math() {423 assert_eq!(424 parse!("2+2*2"),425 el!(Expr::BinaryOp(426 el!(Expr::Num(2.0)),427 Add,428 el!(Expr::BinaryOp(429 el!(Expr::Num(2.0)),430 Mul,431 el!(Expr::Num(2.0))432 ))433 ))434 );435 }436437 #[test]438 fn basic_math_with_indents() {439 assert_eq!(parse!("2 + 2 * 2 "), expressions::basic_math());440 }441442 #[test]443 fn basic_math_parened() {444 assert_eq!(445 parse!("2+(2+2*2)"),446 el!(Expr::BinaryOp(447 el!(Expr::Num(2.0)),448 Add,449 el!(Expr::Parened(expressions::basic_math())),450 ))451 );452 }453454 /// Comments should not affect parsing455 #[test]456 fn comments() {457 assert_eq!(458 parse!("2//comment\n+//comment\n3/*test*/*/*test*/4"),459 el!(Expr::BinaryOp(460 el!(Expr::Num(2.0)),461 Add,462 el!(Expr::BinaryOp(463 el!(Expr::Num(3.0)),464 Mul,465 el!(Expr::Num(4.0))466 ))467 ))468 );469 }470471 /// Comments should be able to be escaped472 #[test]473 fn comment_escaping() {474 assert_eq!(475 parse!("2/*\\*/+*/ - 22"),476 el!(Expr::BinaryOp(477 el!(Expr::Num(2.0)),478 Sub,479 el!(Expr::Num(22.0))480 ))481 );482 }483484 #[test]485 fn suffix() {486 // assert_eq!(parse!("std.test"), el!(Expr::Num(2.2)));487 // assert_eq!(parse!("std(2)"), el!(Expr::Num(2.2)));488 // assert_eq!(parse!("std.test(2)"), el!(Expr::Num(2.2)));489 // assert_eq!(parse!("a[b]"), el!(Expr::Num(2.2)))490 }491492 #[test]493 fn array_comp() {494 use Expr::*;495 assert_eq!(496 parse!("[std.deepJoin(x) for x in arr]"),497 el!(ArrComp(498 el!(Apply(499 el!(Index(el!(Var("std".into())), el!(Str("deepJoin".into())))),500 ArgsDesc::new(vec![el!(Var("x".into()))], vec![]),501 false,502 )),503 vec![CompSpec::ForSpec(ForSpecData(504 "x".into(),505 el!(Var("arr".into()))506 ))]507 )),508 )509 }510511 #[test]512 fn reserved() {513 use Expr::*;514 assert_eq!(parse!("null"), el!(Literal(LiteralType::Null)));515 assert_eq!(parse!("nulla"), el!(Var("nulla".into())));516 }517518 #[test]519 fn multiple_args_buf() {520 parse!("a(b, null_fields)");521 }522523 #[test]524 fn infix_precedence() {525 use Expr::*;526 assert_eq!(527 parse!("!a && !b"),528 el!(BinaryOp(529 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into())))),530 And,531 el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into()))))532 ))533 );534 }535536 #[test]537 fn infix_precedence_division() {538 use Expr::*;539 assert_eq!(540 parse!("!a / !b"),541 el!(BinaryOp(542 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into())))),543 Div,544 el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into()))))545 ))546 );547 }548549 #[test]550 fn double_negation() {551 use Expr::*;552 assert_eq!(553 parse!("!!a"),554 el!(UnaryOp(555 UnaryOpType::Not,556 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()))))557 ))558 )559 }560561 #[test]562 fn array_test_error() {563 parse!("[a for a in b if c for e in f]");564 // ^^^^ failed code565 }566567 #[test]568 fn missing_newline_between_comment_and_eof() {569 parse!(570 "{a:1}571572 //+213"573 );574 }575576 #[test]577 fn default_param_before_nondefault() {578 parse!("local x(foo = 'foo', bar) = null; null");579 }580581 #[test]582 fn can_parse_stdlib() {583 parse!(jrsonnet_stdlib::STDLIB_STR);584 }585586 #[test]587 fn add_location_info_to_all_sub_expressions() {588 use Expr::*;589590 let file_name: std::rc::Rc<std::path::Path> = PathBuf::from("/test.jsonnet").into();591 let expr = parse(592 "{} { local x = 1, x: x } + {}",593 &ParserSettings {594 loc_data: true,595 file_name: file_name.clone(),596 },597 )598 .unwrap();599 assert_eq!(600 expr,601 el_loc!(602 BinaryOp(603 el_loc!(604 ObjExtend(605 el_loc!(606 Obj(ObjBody::MemberList(vec![])),607 ExprLocation(file_name.clone(), 0, 2)608 ),609 ObjBody::MemberList(vec![610 Member::BindStmt(BindSpec {611 name: "x".into(),612 params: None,613 value: el_loc!(614 Num(1.0),615 ExprLocation(file_name.clone(), 15, 16)616 )617 }),618 Member::Field(FieldMember {619 name: FieldName::Fixed("x".into()),620 plus: false,621 params: None,622 visibility: Visibility::Normal,623 value: el_loc!(624 Var("x".into()),625 ExprLocation(file_name.clone(), 21, 22)626 ),627 })628 ])629 ),630 ExprLocation(file_name.clone(), 0, 24)631 ),632 BinaryOpType::Add,633 el_loc!(634 Obj(ObjBody::MemberList(vec![])),635 ExprLocation(file_name.clone(), 27, 29)636 ),637 ),638 ExprLocation(file_name.clone(), 0, 29),639 ),640 );641 }642 // From source code643 /*644 #[bench]645 fn bench_parse_peg(b: &mut Bencher) {646 b.iter(|| parse!(jrsonnet_stdlib::STDLIB_STR))647 }648 */649}1#![allow(clippy::redundant_closure_call)]23use peg::parser;4use std::{5 path::{Path, PathBuf},6 rc::Rc,7};8mod expr;9pub use expr::*;10pub use jrsonnet_interner::IStr;11pub use peg;12mod unescape;1314pub struct ParserSettings {15 pub file_name: Rc<Path>,16}1718macro_rules! expr_bin {19 ($a:ident $op:ident $b:ident) => {20 Expr::BinaryOp($a, $op, $b)21 };22}23macro_rules! expr_un {24 ($op:ident $a:ident) => {25 Expr::UnaryOp($op, $a)26 };27}2829parser! {30 grammar jsonnet_parser() for str {31 use peg::ParseLiteral;3233 rule eof() = quiet!{![_]} / expected!("<eof>")34 rule eol() = "\n" / eof()3536 /// Standard C-like comments37 rule comment()38 = "//" (!eol()[_])* eol()39 / "/*" ("\\*/" / "\\\\" / (!("*/")[_]))* "*/"40 / "#" (!eol()[_])* eol()4142 rule single_whitespace() = quiet!{([' ' | '\r' | '\n' | '\t'] / comment())} / expected!("<whitespace>")43 rule _() = single_whitespace()*4445 /// For comma-delimited elements46 rule comma() = quiet!{_ "," _} / expected!("<comma>")47 rule alpha() -> char = c:$(['_' | 'a'..='z' | 'A'..='Z']) {c.chars().next().unwrap()}48 rule digit() -> char = d:$(['0'..='9']) {d.chars().next().unwrap()}49 rule end_of_ident() = !['0'..='9' | '_' | 'a'..='z' | 'A'..='Z']50 /// Sequence of digits51 rule uint_str() -> &'input str = a:$(digit()+) { a }52 /// Number in scientific notation format53 rule number() -> f64 = quiet!{a:$(uint_str() ("." uint_str())? (['e'|'E'] (s:['+'|'-'])? uint_str())?) {? a.parse().map_err(|_| "<number>") }} / expected!("<number>")5455 /// Reserved word followed by any non-alphanumberic56 rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()57 rule id() = quiet!{ !reserved() alpha() (alpha() / digit())*} / expected!("<identifier>")5859 rule keyword(id: &'static str) -> ()60 = ##parse_string_literal(id) end_of_ident()6162 pub rule param(s: &ParserSettings) -> expr::Param = name:$(id()) expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name.into(), expr) }63 pub rule params(s: &ParserSettings) -> expr::ParamsDesc64 = params:param(s) ** comma() comma()? { expr::ParamsDesc(Rc::new(params)) }65 / { expr::ParamsDesc(Rc::new(Vec::new())) }6667 pub rule arg(s: &ParserSettings) -> (Option<IStr>, LocExpr)68 = quiet! { name:(s:$(id()) _ "=" _ {s})? expr:expr(s) {(name.map(Into::into), expr)} }69 / expected!("<argument>")7071 pub rule args(s: &ParserSettings) -> expr::ArgsDesc72 = args:arg(s)**comma() comma()? {?73 let unnamed_count = args.iter().take_while(|(n, _)| n.is_none()).count();74 let mut unnamed = Vec::with_capacity(unnamed_count);75 let mut named = Vec::with_capacity(args.len() - unnamed_count);76 let mut named_started = false;77 for (name, value) in args {78 if let Some(name) = name {79 named_started = true;80 named.push((name, value));81 } else {82 if named_started {83 return Err("<named argument>")84 }85 unnamed.push(value);86 }87 }88 Ok(expr::ArgsDesc::new(unnamed, named))89 }9091 pub rule bind(s: &ParserSettings) -> expr::BindSpec92 = name:$(id()) _ "=" _ expr:expr(s) {expr::BindSpec{name:name.into(), params: None, value: expr}}93 / name:$(id()) _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec{name:name.into(), params: Some(params), value: expr}}94 pub rule assertion(s: &ParserSettings) -> expr::AssertStmt95 = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) }9697 pub rule whole_line() -> &'input str98 = str:$((!['\n'][_])* "\n") {str}99 pub rule string_block() -> String100 = "|||" (!['\n']single_whitespace())* "\n"101 empty_lines:$(['\n']*)102 prefix:[' ' | '\t']+ first_line:whole_line()103 lines:("\n" {"\n"} / [' ' | '\t']*<{prefix.len()}> s:whole_line() {s})*104 [' ' | '\t']*<, {prefix.len() - 1}> "|||"105 {let mut l = empty_lines.to_owned(); l.push_str(first_line); l.extend(lines); l}106107 rule hex_char()108 = quiet! { ['0'..='9' | 'a'..='f' | 'A'..='F'] } / expected!("<hex char>")109110 rule string_char(c: rule<()>)111 = (!['\\']!c()[_])+112 / "\\\\"113 / "\\u" hex_char() hex_char() hex_char() hex_char()114 / "\\x" hex_char() hex_char()115 / ['\\'] (quiet! { ['b' | 'f' | 'n' | 'r' | 't'] / c() } / expected!("<escape character>"))116 pub rule string() -> String117 = ['"'] str:$(string_char(<['"']>)*) ['"'] {? unescape::unescape(str).ok_or("<escaped string>")}118 / ['\''] str:$(string_char(<['\'']>)*) ['\''] {? unescape::unescape(str).ok_or("<escaped string>")}119 / quiet!{ "@'" str:$(("''" / (!['\''][_]))*) "'" {str.replace("''", "'")}120 / "@\"" str:$(("\"\"" / (!['"'][_]))*) "\"" {str.replace("\"\"", "\"")}121 / string_block() } / expected!("<string>")122123 pub rule field_name(s: &ParserSettings) -> expr::FieldName124 = name:$(id()) {expr::FieldName::Fixed(name.into())}125 / name:string() {expr::FieldName::Fixed(name.into())}126 / "[" _ expr:expr(s) _ "]" {expr::FieldName::Dyn(expr)}127 pub rule visibility() -> expr::Visibility128 = ":::" {expr::Visibility::Unhide}129 / "::" {expr::Visibility::Hidden}130 / ":" {expr::Visibility::Normal}131 pub rule field(s: &ParserSettings) -> expr::FieldMember132 = name:field_name(s) _ plus:"+"? _ visibility:visibility() _ value:expr(s) {expr::FieldMember{133 name,134 plus: plus.is_some(),135 params: None,136 visibility,137 value,138 }}139 / name:field_name(s) _ "(" _ params:params(s) _ ")" _ visibility:visibility() _ value:expr(s) {expr::FieldMember{140 name,141 plus: false,142 params: Some(params),143 visibility,144 value,145 }}146 pub rule obj_local(s: &ParserSettings) -> BindSpec147 = keyword("local") _ bind:bind(s) {bind}148 pub rule member(s: &ParserSettings) -> expr::Member149 = bind:obj_local(s) {expr::Member::BindStmt(bind)}150 / assertion:assertion(s) {expr::Member::AssertStmt(assertion)}151 / field:field(s) {expr::Member::Field(field)}152 pub rule objinside(s: &ParserSettings) -> expr::ObjBody153 = pre_locals:(b: obj_local(s) comma() {b})* "[" _ key:expr(s) _ "]" _ plus:"+"? _ ":" _ value:expr(s) post_locals:(comma() b:obj_local(s) {b})* _ forspec:forspec(s) others:(_ rest:compspec(s) {rest})? {154 let mut compspecs = vec![CompSpec::ForSpec(forspec)];155 compspecs.extend(others.unwrap_or_default());156 expr::ObjBody::ObjComp(expr::ObjComp{157 pre_locals,158 key,159 plus: plus.is_some(),160 value,161 post_locals,162 compspecs,163 })164 }165 / members:(member(s) ** comma()) comma()? {expr::ObjBody::MemberList(members)}166 pub rule ifspec(s: &ParserSettings) -> IfSpecData167 = keyword("if") _ expr:expr(s) {IfSpecData(expr)}168 pub rule forspec(s: &ParserSettings) -> ForSpecData169 = keyword("for") _ id:$(id()) _ keyword("in") _ cond:expr(s) {ForSpecData(id.into(), cond)}170 pub rule compspec(s: &ParserSettings) -> Vec<expr::CompSpec>171 = s:(i:ifspec(s) { expr::CompSpec::IfSpec(i) } / f:forspec(s) {expr::CompSpec::ForSpec(f)} ) ** _ {s}172 pub rule local_expr(s: &ParserSettings) -> Expr173 = keyword("local") _ binds:bind(s) ** comma() _ ";" _ expr:expr(s) { Expr::LocalExpr(binds, expr) }174 pub rule string_expr(s: &ParserSettings) -> Expr175 = s:string() {Expr::Str(s.into())}176 pub rule obj_expr(s: &ParserSettings) -> Expr177 = "{" _ body:objinside(s) _ "}" {Expr::Obj(body)}178 pub rule array_expr(s: &ParserSettings) -> Expr179 = "[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(elems)}180 pub rule array_comp_expr(s: &ParserSettings) -> Expr181 = "[" _ expr:expr(s) _ comma()? _ forspec:forspec(s) _ others:(others: compspec(s) _ {others})? "]" {182 let mut specs = vec![CompSpec::ForSpec(forspec)];183 specs.extend(others.unwrap_or_default());184 Expr::ArrComp(expr, specs)185 }186 pub rule number_expr(s: &ParserSettings) -> Expr187 = n:number() { expr::Expr::Num(n) }188 pub rule var_expr(s: &ParserSettings) -> Expr189 = n:$(id()) { expr::Expr::Var(n.into()) }190 pub rule id_loc(s: &ParserSettings) -> LocExpr191 = a:position!() n:$(id()) b:position!() { LocExpr(Rc::new(expr::Expr::Str(n.into())), ExprLocation(s.file_name.clone(), a,b)) }192 pub rule if_then_else_expr(s: &ParserSettings) -> Expr193 = cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse{194 cond,195 cond_then,196 cond_else,197 }}198199 pub rule literal(s: &ParserSettings) -> Expr200 = v:(201 keyword("null") {LiteralType::Null}202 / keyword("true") {LiteralType::True}203 / keyword("false") {LiteralType::False}204 / keyword("self") {LiteralType::This}205 / keyword("$") {LiteralType::Dollar}206 / keyword("super") {LiteralType::Super}207 ) {Expr::Literal(v)}208209 pub rule expr_basic(s: &ParserSettings) -> Expr210 = literal(s)211212 / quiet!{"$intrinsic(" name:$(id()) ")" {Expr::Intrinsic(name.into())}}213214 / string_expr(s) / number_expr(s)215 / array_expr(s)216 / obj_expr(s)217 / array_expr(s)218 / array_comp_expr(s)219220 / keyword("importstr") _ path:string() {Expr::ImportStr(PathBuf::from(path))}221 / keyword("import") _ path:string() {Expr::Import(PathBuf::from(path))}222223 / var_expr(s)224 / local_expr(s)225 / if_then_else_expr(s)226227 / keyword("function") _ "(" _ params:params(s) _ ")" _ expr:expr(s) {Expr::Function(params, expr)}228 / assertion:assertion(s) _ ";" _ expr:expr(s) { Expr::AssertExpr(assertion, expr) }229230 / keyword("error") _ expr:expr(s) { Expr::ErrorStmt(expr) }231232 rule slice_part(s: &ParserSettings) -> Option<LocExpr>233 = e:(_ e:expr(s) _{e})? {e}234 pub rule slice_desc(s: &ParserSettings) -> SliceDesc235 = start:slice_part(s) ":" pair:(end:slice_part(s) step:(":" e:slice_part(s){e})? {(end, step.flatten())})? {236 let (end, step) = if let Some((end, step)) = pair {237 (end, step)238 }else{239 (None, None)240 };241242 SliceDesc { start, end, step }243 }244245 rule binop(x: rule<()>) -> ()246 = quiet!{ x() } / expected!("<binary op>")247 rule unaryop(x: rule<()>) -> ()248 = quiet!{ x() } / expected!("<unary op>")249250251 use BinaryOpType::*;252 use UnaryOpType::*;253 rule expr(s: &ParserSettings) -> LocExpr254 = precedence! {255 start:position!() v:@ end:position!() { LocExpr(Rc::new(v), ExprLocation(s.file_name.clone(), start, end)) }256 --257 a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)}258 --259 a:(@) _ binop(<"&&">) _ b:@ {expr_bin!(a And b)}260 --261 a:(@) _ binop(<"|">) _ b:@ {expr_bin!(a BitOr b)}262 --263 a:@ _ binop(<"^">) _ b:(@) {expr_bin!(a BitXor b)}264 --265 a:(@) _ binop(<"&">) _ b:@ {expr_bin!(a BitAnd b)}266 --267 a:(@) _ binop(<"==">) _ b:@ {expr_bin!(a Eq b)}268 a:(@) _ binop(<"!=">) _ b:@ {expr_bin!(a Neq b)}269 --270 a:(@) _ binop(<"<">) _ b:@ {expr_bin!(a Lt b)}271 a:(@) _ binop(<">">) _ b:@ {expr_bin!(a Gt b)}272 a:(@) _ binop(<"<=">) _ b:@ {expr_bin!(a Lte b)}273 a:(@) _ binop(<">=">) _ b:@ {expr_bin!(a Gte b)}274 a:(@) _ binop(<keyword("in")>) _ b:@ {expr_bin!(a In b)}275 --276 a:(@) _ binop(<"<<">) _ b:@ {expr_bin!(a Lhs b)}277 a:(@) _ binop(<">>">) _ b:@ {expr_bin!(a Rhs b)}278 --279 a:(@) _ binop(<"+">) _ b:@ {expr_bin!(a Add b)}280 a:(@) _ binop(<"-">) _ b:@ {expr_bin!(a Sub b)}281 --282 a:(@) _ binop(<"*">) _ b:@ {expr_bin!(a Mul b)}283 a:(@) _ binop(<"/">) _ b:@ {expr_bin!(a Div b)}284 a:(@) _ binop(<"%">) _ b:@ {expr_bin!(a Mod b)}285 --286 unaryop(<"-">) _ b:@ {expr_un!(Minus b)}287 unaryop(<"!">) _ b:@ {expr_un!(Not b)}288 unaryop(<"~">) _ b:@ {expr_un!(BitNot b)}289 --290 a:(@) _ "[" _ e:slice_desc(s) _ "]" {Expr::Slice(a, e)}291 a:(@) _ "." _ a:position!() e:id_loc(s) b:position!() {Expr::Index(a, e)}292 a:(@) _ "[" _ e:expr(s) _ "]" {Expr::Index(a, e)}293 a:(@) _ "(" _ args:args(s) _ ")" ts:(_ keyword("tailstrict"))? {Expr::Apply(a, args, ts.is_some())}294 a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(a, body)}295 --296 e:expr_basic(s) {e}297 "(" _ e:expr(s) _ ")" {Expr::Parened(e)}298 }299300 pub rule jsonnet(s: &ParserSettings) -> LocExpr = _ e:expr(s) _ {e}301 }302}303304pub type ParseError = peg::error::ParseError<peg::str::LineCol>;305pub fn parse(str: &str, settings: &ParserSettings) -> Result<LocExpr, ParseError> {306 jsonnet_parser::jsonnet(str, settings)307}308309#[cfg(test)]310pub mod tests {311 use super::{expr::*, parse};312 use crate::ParserSettings;313 use std::path::PathBuf;314 use BinaryOpType::*;315316 macro_rules! parse {317 ($s:expr) => {318 parse(319 $s,320 &ParserSettings {321 file_name: PathBuf::from("test.jsonnet").into(),322 },323 )324 .unwrap()325 };326 }327328 macro_rules! el {329 ($expr:expr, $from:expr, $to:expr$(,)?) => {330 LocExpr(331 std::rc::Rc::new($expr),332 ExprLocation(PathBuf::from("test.jsonnet").into(), $from, $to),333 )334 };335 }336337 #[test]338 fn multiline_string() {339 assert_eq!(340 parse!("|||\n Hello world!\n a\n|||"),341 el!(Expr::Str("Hello world!\n a\n".into()), 0, 31),342 );343 assert_eq!(344 parse!("|||\n Hello world!\n a\n|||"),345 el!(Expr::Str("Hello world!\n a\n".into()), 0, 27),346 );347 assert_eq!(348 parse!("|||\n\t\tHello world!\n\t\t\ta\n|||"),349 el!(Expr::Str("Hello world!\n\ta\n".into()), 0, 27),350 );351 assert_eq!(352 parse!("|||\n Hello world!\n a\n |||"),353 el!(Expr::Str("Hello world!\n a\n".into()), 0, 30),354 );355 }356357 #[test]358 fn slice() {359 parse!("a[1:]");360 parse!("a[1::]");361 parse!("a[:1:]");362 parse!("a[::1]");363 parse!("str[:len - 1]");364 }365366 #[test]367 fn string_escaping() {368 assert_eq!(369 parse!(r#""Hello, \"world\"!""#),370 el!(Expr::Str(r#"Hello, "world"!"#.into()), 0, 19),371 );372 assert_eq!(373 parse!(r#"'Hello \'world\'!'"#),374 el!(Expr::Str("Hello 'world'!".into()), 0, 18),375 );376 assert_eq!(parse!(r#"'\\\\'"#), el!(Expr::Str("\\\\".into()), 0, 6));377 }378379 #[test]380 fn string_unescaping() {381 assert_eq!(382 parse!(r#""Hello\nWorld""#),383 el!(Expr::Str("Hello\nWorld".into()), 0, 14),384 );385 }386387 #[test]388 fn string_verbantim() {389 assert_eq!(390 parse!(r#"@"Hello\n""World""""#),391 el!(Expr::Str("Hello\\n\"World\"".into()), 0, 19),392 );393 }394395 #[test]396 fn imports() {397 assert_eq!(398 parse!("import \"hello\""),399 el!(Expr::Import(PathBuf::from("hello")), 0, 14),400 );401 assert_eq!(402 parse!("importstr \"garnish.txt\""),403 el!(Expr::ImportStr(PathBuf::from("garnish.txt")), 0, 23)404 );405 }406407 #[test]408 fn empty_object() {409 assert_eq!(410 parse!("{}"),411 el!(Expr::Obj(ObjBody::MemberList(vec![])), 0, 2)412 );413 }414415 #[test]416 fn basic_math() {417 assert_eq!(418 parse!("2+2*2"),419 el!(420 Expr::BinaryOp(421 el!(Expr::Num(2.0), 0, 1),422 Add,423 el!(424 Expr::BinaryOp(el!(Expr::Num(2.0), 2, 3), Mul, el!(Expr::Num(2.0), 4, 5)),425 2,426 5427 )428 ),429 0,430 5431 )432 );433 }434435 #[test]436 fn basic_math_with_indents() {437 assert_eq!(438 parse!("2 + 2 * 2 "),439 el!(440 Expr::BinaryOp(441 el!(Expr::Num(2.0), 0, 1),442 Add,443 el!(444 Expr::BinaryOp(el!(Expr::Num(2.0), 7, 8), Mul, el!(Expr::Num(2.0), 13, 14),),445 7,446 14447 ),448 ),449 0,450 14451 )452 );453 }454455 #[test]456 fn basic_math_parened() {457 assert_eq!(458 parse!("2+(2+2*2)"),459 el!(460 Expr::BinaryOp(461 el!(Expr::Num(2.0), 0, 1),462 Add,463 el!(464 Expr::Parened(el!(465 Expr::BinaryOp(466 el!(Expr::Num(2.0), 3, 4),467 Add,468 el!(469 Expr::BinaryOp(470 el!(Expr::Num(2.0), 5, 6),471 Mul,472 el!(Expr::Num(2.0), 7, 8),473 ),474 5,475 8476 ),477 ),478 3,479 8480 )),481 2,482 9483 ),484 ),485 0,486 9487 )488 );489 }490491 /// Comments should not affect parsing492 #[test]493 fn comments() {494 assert_eq!(495 parse!("2//comment\n+//comment\n3/*test*/*/*test*/4"),496 el!(497 Expr::BinaryOp(498 el!(Expr::Num(2.0), 0, 1),499 Add,500 el!(501 Expr::BinaryOp(502 el!(Expr::Num(3.0), 22, 23),503 Mul,504 el!(Expr::Num(4.0), 40, 41)505 ),506 22,507 41508 )509 ),510 0,511 41512 )513 );514 }515516 /// Comments should be able to be escaped517 #[test]518 fn comment_escaping() {519 assert_eq!(520 parse!("2/*\\*/+*/ - 22"),521 el!(522 Expr::BinaryOp(el!(Expr::Num(2.0), 0, 1), Sub, el!(Expr::Num(22.0), 12, 14)),523 0,524 14525 )526 );527 }528529 #[test]530 fn suffix() {531 // assert_eq!(parse!("std.test"), el!(Expr::Num(2.2)));532 // assert_eq!(parse!("std(2)"), el!(Expr::Num(2.2)));533 // assert_eq!(parse!("std.test(2)"), el!(Expr::Num(2.2)));534 // assert_eq!(parse!("a[b]"), el!(Expr::Num(2.2)))535 }536537 #[test]538 fn array_comp() {539 use Expr::*;540 /*541 `ArrComp(Apply(Index(Var("std") from "test.jsonnet":1-4, Var("deepJoin") from "test.jsonnet":5-13) from "test.jsonnet":1-13, ArgsDesc { unnamed: [Var("x") from "test.jsonnet":14-15], named: [] }, false) from "test.jsonnet":1-16, [ForSpec(ForSpecData("x", Var("arr") from "test.jsonnet":26-29))]) from "test.jsonnet":0-30`,542 `ArrComp(Apply(Index(Var("std") from "test.jsonnet":1-4, Str("deepJoin") from "test.jsonnet":5-13) from "test.jsonnet":1-13, ArgsDesc { unnamed: [Var("x") from "test.jsonnet":14-15], named: [] }, false) from "test.jsonnet":1-16, [ForSpec(ForSpecData("x", Var("arr") from "test.jsonnet":26-29))]) from "test.jsonnet":0-30`543 */544 assert_eq!(545 parse!("[std.deepJoin(x) for x in arr]"),546 el!(547 ArrComp(548 el!(549 Apply(550 el!(551 Index(552 el!(Var("std".into()), 1, 4),553 el!(Str("deepJoin".into()), 5, 13)554 ),555 1,556 13557 ),558 ArgsDesc::new(vec![el!(Var("x".into()), 14, 15)], vec![]),559 false,560 ),561 1,562 16563 ),564 vec![CompSpec::ForSpec(ForSpecData(565 "x".into(),566 el!(Var("arr".into()), 26, 29)567 ))]568 ),569 0,570 30571 ),572 )573 }574575 #[test]576 fn reserved() {577 use Expr::*;578 assert_eq!(parse!("null"), el!(Literal(LiteralType::Null), 0, 4));579 assert_eq!(parse!("nulla"), el!(Var("nulla".into()), 0, 5));580 }581582 #[test]583 fn multiple_args_buf() {584 parse!("a(b, null_fields)");585 }586587 #[test]588 fn infix_precedence() {589 use Expr::*;590 assert_eq!(591 parse!("!a && !b"),592 el!(593 BinaryOp(594 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()), 1, 2)), 0, 2),595 And,596 el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into()), 7, 8)), 6, 8)597 ),598 0,599 8600 )601 );602 }603604 #[test]605 fn infix_precedence_division() {606 use Expr::*;607 assert_eq!(608 parse!("!a / !b"),609 el!(610 BinaryOp(611 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()), 1, 2)), 0, 2),612 Div,613 el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into()), 6, 7)), 5, 7)614 ),615 0,616 7617 )618 );619 }620621 #[test]622 fn double_negation() {623 use Expr::*;624 assert_eq!(625 parse!("!!a"),626 el!(627 UnaryOp(628 UnaryOpType::Not,629 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()), 2, 3)), 1, 3)630 ),631 0,632 3633 )634 )635 }636637 #[test]638 fn array_test_error() {639 parse!("[a for a in b if c for e in f]");640 // ^^^^ failed code641 }642643 #[test]644 fn missing_newline_between_comment_and_eof() {645 parse!(646 "{a:1}647648 //+213"649 );650 }651652 #[test]653 fn default_param_before_nondefault() {654 parse!("local x(foo = 'foo', bar) = null; null");655 }656657 #[test]658 fn can_parse_stdlib() {659 parse!(jrsonnet_stdlib::STDLIB_STR);660 }661662 #[test]663 fn add_location_info_to_all_sub_expressions() {664 use Expr::*;665666 let file_name: std::rc::Rc<std::path::Path> = PathBuf::from("test.jsonnet").into();667 let expr = parse(668 "{} { local x = 1, x: x } + {}",669 &ParserSettings {670 file_name: file_name.clone(),671 },672 )673 .unwrap();674 assert_eq!(675 expr,676 el!(677 BinaryOp(678 el!(679 ObjExtend(680 el!(Obj(ObjBody::MemberList(vec![])), 0, 2),681 ObjBody::MemberList(vec![682 Member::BindStmt(BindSpec {683 name: "x".into(),684 params: None,685 value: el!(Num(1.0), 15, 16)686 }),687 Member::Field(FieldMember {688 name: FieldName::Fixed("x".into()),689 plus: false,690 params: None,691 visibility: Visibility::Normal,692 value: el!(Var("x".into()), 21, 22),693 })694 ])695 ),696 0,697 24698 ),699 BinaryOpType::Add,700 el!(Obj(ObjBody::MemberList(vec![])), 27, 29),701 ),702 0,703 29704 ),705 );706 }707 // From source code708 /*709 #[bench]710 fn bench_parse_peg(b: &mut Bencher) {711 b.iter(|| parse!(jrsonnet_stdlib::STDLIB_STR))712 }713 */714}crates/jrsonnet-parser/src/unescape.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-parser/src/unescape.rs
@@ -0,0 +1,38 @@
+pub fn unescape(s: &str) -> Option<String> {
+ let mut chars = s.chars();
+ let mut out = String::with_capacity(s.len());
+
+ while let Some(c) = chars.next() {
+ if c != '\\' {
+ out.push(c);
+ continue;
+ }
+ match chars.next()? {
+ c @ ('\\' | '"' | '\'') => out.push(c),
+ 'b' => out.push('\u{0008}'),
+ 'f' => out.push('\u{000c}'),
+ 'n' => out.push('\n'),
+ 'r' => out.push('\r'),
+ 't' => out.push('\t'),
+ 'u' => {
+ let c = IntoIterator::into_iter([
+ chars.next()?,
+ chars.next()?,
+ chars.next()?,
+ chars.next()?,
+ ])
+ .map(|c| c.to_digit(16))
+ .try_fold(0u32, |acc, v| Some((acc << 8) | (v?)))?;
+ out.push(char::from_u32(c)?)
+ }
+ 'x' => {
+ let c = IntoIterator::into_iter([chars.next()?, chars.next()?])
+ .map(|c| c.to_digit(16))
+ .try_fold(0u32, |acc, v| Some((acc << 8) | (v?)))?;
+ out.push(char::from_u32(c)?)
+ }
+ _ => return None,
+ }
+ }
+ Some(out)
+}
crates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/std.jsonnet
+++ b/crates/jrsonnet-stdlib/src/std.jsonnet
@@ -370,7 +370,7 @@
ch;
std.foldl(function(a, b) a + trans(b), std.stringChars(str), ''),
- manifestJson(value):: std.manifestJsonEx(value, ' '),
+ manifestJson(value):: std.manifestJsonEx(value, ' ') tailstrict,
manifestJsonEx:: $intrinsic(manifestJsonEx),
crates/jrsonnet-types/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-types/Cargo.toml
+++ b/crates/jrsonnet-types/Cargo.toml
@@ -8,4 +8,4 @@
[dependencies]
peg = "0.7.0"
-jrsonnet-gc = { version = "0.4.2", features = ["derive"] }
+gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" }
crates/jrsonnet-types/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-types/src/lib.rs
+++ b/crates/jrsonnet-types/src/lib.rs
@@ -1,6 +1,6 @@
#![allow(clippy::redundant_closure_call)]
-use jrsonnet_gc::Trace;
+use gcmodule::Trace;
use std::fmt::Display;
#[macro_export]
@@ -82,7 +82,6 @@
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]
-#[trivially_drop]
pub enum ValType {
Bool,
Null,
@@ -115,7 +114,7 @@
}
#[derive(Debug, Clone, PartialEq, Trace)]
-#[trivially_drop]
+#[skip_trace]
pub enum ComplexValType {
Any,
Char,