feat: allow calling generic methods.
This commit is contained in:
parent
4eb6ec1a04
commit
6d62f6eeb0
2 changed files with 67 additions and 1 deletions
|
@ -112,6 +112,9 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
|
|||
}
|
||||
|
||||
public class Builtins : Dictionary<string, Function> {
|
||||
|
||||
private static Dictionary<string, Assembly> AssemblyMapping = new Dictionary<string, Assembly>();
|
||||
|
||||
public Builtins() : base() {
|
||||
this["atom"] = _atom;
|
||||
this["eq"] = _eq;
|
||||
|
@ -147,6 +150,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
|
|||
this["haskeys"] = _haskeys;
|
||||
this["getitems"] = _getitems;
|
||||
this["invoke"] = _invoke;
|
||||
this["invoke-generic"] = _invoke_generic;
|
||||
}
|
||||
private static T _agg<T>(Func<T, T, T> op, IEnumerable<Expression> args) where T : Expression {
|
||||
T agg = (T) args.First();
|
||||
|
@ -250,11 +254,68 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
|
|||
IList<Expression> r = new List<Expression>();
|
||||
MethodInfo? mi = o.Value().GetType().GetMethod(s.Value(), l_types);
|
||||
if (mi == null) {
|
||||
throw new ApplicationException($"{o.Value()} has not method {s.Value()}");
|
||||
throw new ApplicationException($"{o.Value()} has no method {s.Value()}");
|
||||
}
|
||||
|
||||
return Object.FromBase(mi.Invoke(o.Value(), l_));
|
||||
}
|
||||
|
||||
private static Type? GetType(string name) {
|
||||
return Type.GetType(
|
||||
name,
|
||||
(name) => { return AppDomain.CurrentDomain.GetAssemblies().Where(z => z.FullName == name.FullName).FirstOrDefault(); },
|
||||
null,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
private static Expression _invoke_generic(IEnumerable<Expression> args) {
|
||||
Object o = new Object(((IInner) args.First()).Inner());
|
||||
String s = (String) args.Skip(1).First();
|
||||
IEnumerable<Expression> l;
|
||||
if (args.Skip(2).First() is Boolean lb && lb == Boolean.FALSE) {
|
||||
l = new List<Expression>();
|
||||
} else if (args.Skip(2).First() is Cons lc) {
|
||||
l = lc.ToList();
|
||||
} else {
|
||||
throw new ApplicationException($"Expected a list of arguments, got {args.Skip(2).First()}");
|
||||
}
|
||||
IEnumerable<Type> types;
|
||||
if (args.Skip(3).First() is Boolean lb_ && lb_ == Boolean.FALSE) {
|
||||
types = new List<Type>();
|
||||
} else if (args.Skip(3).First() is Cons lc) {
|
||||
types = lc.ToList().Select(x => GetType(((String) x).Value())).ToList();
|
||||
} else {
|
||||
throw new ApplicationException($"Expected a list of arguments, got {args.Skip(3).First()}");
|
||||
}
|
||||
object[]? l_ = l.Select<Expression, object>(x => {
|
||||
switch (x) {
|
||||
case Integer s:
|
||||
return s.Value();
|
||||
case Boolean b:
|
||||
return b.Value();
|
||||
case String s:
|
||||
return s.Value();
|
||||
case Object o:
|
||||
return o.Value();
|
||||
case Cons c:
|
||||
return c.ToList().ToList();
|
||||
}
|
||||
throw new ApplicationException($"Unhandled value {x} (type {x.GetType()})");
|
||||
}).ToArray();
|
||||
Type[] l_types = l_.Select( x => {
|
||||
return x.GetType();
|
||||
}).ToArray();
|
||||
|
||||
IList<Expression> r = new List<Expression>();
|
||||
MethodInfo? mi = o.Value().GetType().GetMethod(s.Value(), l_types);
|
||||
if (mi == null) {
|
||||
throw new ApplicationException($"{o.Value()} has no method {s.Value()}");
|
||||
}
|
||||
mi = mi.MakeGenericMethod(types.ToArray());
|
||||
|
||||
return Object.FromBase(mi.Invoke(o.Value(), l_));
|
||||
}
|
||||
}
|
||||
|
||||
public class BuiltinsLater : Dictionary<string, FunctionLater> {
|
||||
|
|
|
@ -17,6 +17,9 @@ namespace Tests
|
|||
public int I() {
|
||||
return _i;
|
||||
}
|
||||
public string G<E>() {
|
||||
return typeof(E).FullName;
|
||||
}
|
||||
}
|
||||
|
||||
public class Test {
|
||||
|
@ -202,6 +205,8 @@ namespace Tests
|
|||
Assert.Equal("(5 nil)", string.Format("{0}", r));
|
||||
r = e.eval("""(invoke o "I" nil)""");
|
||||
Assert.Equal("5", string.Format("{0}", r));
|
||||
r = e.eval("""(invoke-generic o "G" nil ((lambda (. args) args) "System.String"))""");
|
||||
Assert.Equal("\"System.String\"", string.Format("{0}", r));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
Loading…
Reference in a new issue