/// <summary> /// Look up a named value. If there is no value with the given /// <paramref name="name"/> (and optional <paramref name="qualifier"/>), /// an exception is thrown. /// </summary> /// <param name="name">The name, required.</param> /// <param name="qualifier">The qualifier, optional.</param> /// <returns> /// The value bound to the given name. /// </returns> public override object Lookup(string name, string qualifier) { if (string.IsNullOrEmpty(qualifier)) { object value; if (_values.TryGetValue(name, out value)) { return(value); } var funKey = new FunKey(name); if (_functions.ContainsKey(funKey)) { return(new Function(name)); } value = LookupUniqueField(name); return(value == DBNull.Value ? null : value); } if (_rows.TryGetValue(qualifier, out INamedValues row)) { if (row.Exists(name)) { object value = row.GetValue(name); return(value == DBNull.Value ? null : value); } } throw LookupError("No such field: {0}.{1}", qualifier, name); }
/// <summary> /// Register the given function (<paramref name="methodInfo"/>) /// with the given <paramref name="name"/> in this environment. /// <para/> /// You can register more than one function with the same name, /// if the functions differ in their number of parameters (arity). /// The evaluator will choose the actual function by the actual /// number of arguments at the time of invocation. /// </summary> /// <param name="name">The name (required)</param> /// <param name="methodInfo">The method (required)</param> /// <param name="state">The method's state (required for non-static methods)</param> /// <remarks> /// Later registrations overwrite earlier registrations /// for the same name/arity combination. /// <para/> /// The method can be static or instance or lambda; <paramref name="state"/> /// will be the implicit "this" parameter passed to all non-static methods /// (static methods ignore this parameter). /// <para/> /// The method need not be public (it is invoked through reflection). /// </remarks> public void Register(string name, MethodInfo methodInfo, object state = null) { Assert.ArgumentNotNullOrEmpty(name, nameof(name)); Assert.ArgumentNotNull(methodInfo, nameof(methodInfo)); var nameKey = new FunKey(name); int arity = GetArity(methodInfo); _functions[nameKey] = null; var funKey = new FunKey(name, arity); _functions[funKey] = new Closure(methodInfo, state); }
/// <summary> /// Invoke the given <paramref name="function"/> with the given /// <paramref name="args"/> and return the resulting value. /// </summary> /// <param name="function"></param> /// <param name="args"></param> /// <returns></returns> /// <remarks> /// The function's parameters and the arguments passed must agree. /// If several functions with the same name were registered, the /// one with the same number of parameters as arguments are passed /// will be called. If there's no function with as many parameters /// as there are arguments, but there's a function with exactly /// one parameter of type array of object, then it will be called. /// Otherwise, an exception will be thrown. /// </remarks> public override object Invoke(Function function, params object[] args) { string name = function.Name; int arity = args?.Length ?? 0; Closure closure; var key = new FunKey(name, arity); if (_functions.TryGetValue(key, out closure)) { return(closure.Invoke(args)); } key = new FunKey(name, -1); // varargs if (_functions.TryGetValue(key, out closure)) { return(closure.Invoke(new object[] { args })); } throw InvocationError("No such function: {0}/{1}", function.Name, arity); }