difftreelog
feat(evaluator) function signature help
in: master
When calling functions with wrong arguments, evaluator will now suggest correct function signature
2 files changed
crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -32,6 +32,31 @@
out
}
+fn format_signature(sig: &FunctionSignature) -> String {
+ let mut out = String::new();
+ out.push_str("\nFunction has the following signature: ");
+ out.push('(');
+ if sig.is_empty() {
+ out.push_str("/*no arguments*/");
+ } else {
+ for (i, (name, has_default)) in sig.iter().enumerate() {
+ if i != 0 {
+ out.push_str(", ");
+ }
+ if let Some(name) = name {
+ out.push_str(name);
+ } else {
+ out.push_str("<unnamed>");
+ }
+ if *has_default {
+ out.push_str(" = <default>");
+ }
+ }
+ }
+ out.push(')');
+ out
+}
+
const fn format_empty_str(str: &str) -> &str {
if str.is_empty() {
"\"\" (empty string)"
@@ -40,6 +65,8 @@
}
}
+type FunctionSignature = Vec<(Option<IStr>, bool)>;
+
#[derive(Error, Debug, Clone, Trace)]
pub enum Error {
#[error("intrinsic not found: {0}")]
@@ -84,10 +111,10 @@
UnknownFunctionParameter(String),
#[error("argument {0} is already bound")]
BindingParameterASecondTime(IStr),
- #[error("too many args, function has {0}")]
- TooManyArgsFunctionHas(usize),
- #[error("function argument is not passed: {0}")]
- FunctionParameterNotBoundInCall(IStr),
+ #[error("too many args, function has {0}{}", format_signature(.1))]
+ TooManyArgsFunctionHas(usize, FunctionSignature),
+ #[error("function argument is not passed: {0}{}", format_signature(.1))]
+ FunctionParameterNotBoundInCall(IStr, FunctionSignature),
#[error("external variable is not defined: {0}")]
UndefinedExternalVariable(IStr),
crates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth49 let mut passed_args = GcHashMap::with_capacity(params.len());49 let mut passed_args = GcHashMap::with_capacity(params.len());50 if args.unnamed_len() > params.len() {50 if args.unnamed_len() > params.len() {51 throw!(TooManyArgsFunctionHas(params.len()))51 throw!(TooManyArgsFunctionHas(52 params.len(),53 params.iter().map(|p| (p.0.name(), p.1.is_some())).collect()54 ))52 }55 }5356126 .0129 .0127 .clone()130 .clone()128 .name()131 .name()129 .unwrap_or_else(|| "<destruct>".into())132 .unwrap_or_else(|| "<destruct>".into()),133 params.iter().map(|p| (p.0.name(), p.1.is_some())).collect()130 ));134 ));131 }135 }132 }136 }160 let mut passed_args = GcHashMap::with_capacity(params.len());164 let mut passed_args = GcHashMap::with_capacity(params.len());161 if args.unnamed_len() > params.len() {165 if args.unnamed_len() > params.len() {162 throw!(TooManyArgsFunctionHas(params.len()))166 throw!(TooManyArgsFunctionHas(167 params.len(),168 params169 .iter()170 .map(|p| (Some(p.name.as_ref().into()), p.has_default))171 .collect()172 ))163 }173 }164174203 });213 });204 if !found {214 if !found {205 throw!(FunctionParameterNotBoundInCall(param.name.clone().into()));215 throw!(FunctionParameterNotBoundInCall(216 param.name.clone().into(),217 params218 .iter()219 .map(|p| (Some(p.name.as_ref().into()), p.has_default))220 .collect()221 ));206 }222 }207 }223 }215/// and with unbound values causing error to be returned231/// and with unbound values causing error to be returned216pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Result<Context> {232pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Result<Context> {217 #[derive(Trace)]233 #[derive(Trace)]218 struct DependsOnUnbound(IStr);234 struct DependsOnUnbound(IStr, ParamsDesc);219 impl ThunkValue for DependsOnUnbound {235 impl ThunkValue for DependsOnUnbound {220 type Output = Val;236 type Output = Val;221 fn get(self: Box<Self>, _: State) -> Result<Val> {237 fn get(self: Box<Self>, _: State) -> Result<Val> {222 Err(FunctionParameterNotBoundInCall(self.0.clone()).into())238 Err(FunctionParameterNotBoundInCall(239 self.0.clone(),240 self.1.iter().map(|p| (p.0.name(), p.1.is_some())).collect(),241 )242 .into())223 }243 }243 destruct(263 destruct(244 ¶m.0,264 ¶m.0,245 Thunk::new(tb!(DependsOnUnbound(265 Thunk::new(tb!(DependsOnUnbound(246 param.0.name().unwrap_or_else(|| "<destruct>".into())266 param.0.name().unwrap_or_else(|| "<destruct>".into()),267 params.clone()247 ))),268 ))),248 fctx.clone(),269 fctx.clone(),249 &mut bindings,270 &mut bindings,