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> {
|
public class Builtins : Dictionary<string, Function> {
|
||||||
|
|
||||||
|
private static Dictionary<string, Assembly> AssemblyMapping = new Dictionary<string, Assembly>();
|
||||||
|
|
||||||
public Builtins() : base() {
|
public Builtins() : base() {
|
||||||
this["atom"] = _atom;
|
this["atom"] = _atom;
|
||||||
this["eq"] = _eq;
|
this["eq"] = _eq;
|
||||||
|
@ -147,6 +150,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
|
||||||
this["haskeys"] = _haskeys;
|
this["haskeys"] = _haskeys;
|
||||||
this["getitems"] = _getitems;
|
this["getitems"] = _getitems;
|
||||||
this["invoke"] = _invoke;
|
this["invoke"] = _invoke;
|
||||||
|
this["invoke-generic"] = _invoke_generic;
|
||||||
}
|
}
|
||||||
private static T _agg<T>(Func<T, T, T> op, IEnumerable<Expression> args) where T : Expression {
|
private static T _agg<T>(Func<T, T, T> op, IEnumerable<Expression> args) where T : Expression {
|
||||||
T agg = (T) args.First();
|
T agg = (T) args.First();
|
||||||
|
@ -250,11 +254,68 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
|
||||||
IList<Expression> r = new List<Expression>();
|
IList<Expression> r = new List<Expression>();
|
||||||
MethodInfo? mi = o.Value().GetType().GetMethod(s.Value(), l_types);
|
MethodInfo? mi = o.Value().GetType().GetMethod(s.Value(), l_types);
|
||||||
if (mi == null) {
|
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_));
|
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> {
|
public class BuiltinsLater : Dictionary<string, FunctionLater> {
|
||||||
|
|
|
@ -17,6 +17,9 @@ namespace Tests
|
||||||
public int I() {
|
public int I() {
|
||||||
return _i;
|
return _i;
|
||||||
}
|
}
|
||||||
|
public string G<E>() {
|
||||||
|
return typeof(E).FullName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Test {
|
public class Test {
|
||||||
|
@ -202,6 +205,8 @@ namespace Tests
|
||||||
Assert.Equal("(5 nil)", string.Format("{0}", r));
|
Assert.Equal("(5 nil)", string.Format("{0}", r));
|
||||||
r = e.eval("""(invoke o "I" nil)""");
|
r = e.eval("""(invoke o "I" nil)""");
|
||||||
Assert.Equal("5", string.Format("{0}", r));
|
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]
|
[Fact]
|
||||||
|
|
Loading…
Reference in a new issue