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.rsdiffbeforeafterboth32 out32 out33}33}3435fn format_signature(sig: &FunctionSignature) -> String {36 let mut out = String::new();37 out.push_str("\nFunction has the following signature: ");38 out.push('(');39 if sig.is_empty() {40 out.push_str("/*no arguments*/");41 } else {42 for (i, (name, has_default)) in sig.iter().enumerate() {43 if i != 0 {44 out.push_str(", ");45 }46 if let Some(name) = name {47 out.push_str(name);48 } else {49 out.push_str("<unnamed>");50 }51 if *has_default {52 out.push_str(" = <default>");53 }54 }55 }56 out.push(')');57 out58}345935const fn format_empty_str(str: &str) -> &str {60const fn format_empty_str(str: &str) -> &str {36 if str.is_empty() {61 if str.is_empty() {40 }65 }41}66}6768type FunctionSignature = Vec<(Option<IStr>, bool)>;426943#[derive(Error, Debug, Clone, Trace)]70#[derive(Error, Debug, Clone, Trace)]44pub enum Error {71pub enum Error {84 UnknownFunctionParameter(String),111 UnknownFunctionParameter(String),85 #[error("argument {0} is already bound")]112 #[error("argument {0} is already bound")]86 BindingParameterASecondTime(IStr),113 BindingParameterASecondTime(IStr),87 #[error("too many args, function has {0}")]114 #[error("too many args, function has {0}{}", format_signature(.1))]88 TooManyArgsFunctionHas(usize),115 TooManyArgsFunctionHas(usize, FunctionSignature),89 #[error("function argument is not passed: {0}")]116 #[error("function argument is not passed: {0}{}", format_signature(.1))]90 FunctionParameterNotBoundInCall(IStr),117 FunctionParameterNotBoundInCall(IStr, FunctionSignature),9111892 #[error("external variable is not defined: {0}")]119 #[error("external variable is not defined: {0}")]93 UndefinedExternalVariable(IStr),120 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,