fix: parsing of multi-character operators and tests.

This commit is contained in:
redxef 2024-10-25 20:20:18 +02:00
parent 1be3b17bae
commit eb45ed5772
Signed by: redxef
GPG key ID: 7DAC3AA211CBD921
4 changed files with 60 additions and 10 deletions

View file

@ -276,7 +276,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
case AtomToken at:
return parse_atom(at);
case OperatorToken ot:
return new Symbol(ot.value);
return parse_operator(ot);
case SpaceToken sp:
return parse();
}
@ -330,5 +330,19 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
_sts.commit();
return new Symbol(at.value);
}
Expression parse_operator(OperatorToken ot) {
string v = ot.value;
while (_sts.available() > 0) {
Token<string> t = _sts.get();
if (t is OperatorToken ot_) {
v += ot_.value;
continue;
}
_sts.rewind(1);
break;
}
return new Symbol(v);
}
}
}

View file

@ -27,6 +27,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
this["car"] = _car;
this["cdr"] = _cdr;
this["cons"] = _cons;
this["not"] = _not;
this["length"] = _length;
this["haskeys"] = _haskeys;
this["getitems"] = _getitems;
@ -170,6 +171,12 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
}
throw new ApplicationException();
}
private static Expression _not(IList<Expression> args) {
if (args[0] == new Compiler.Boolean(false)) {
return new Compiler.Boolean(true);
}
return new Compiler.Boolean(false);
}
private static Expression _length(IList<Expression> args) {
return new Integer(((Compiler.List)args[0]).expressions.Count());
}
@ -231,9 +238,11 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
this["if"] = _if;
this["define"] = _define;
this["apply"] = _apply;
this["and"] = _and;
this["or"] = _or;
}
private static Expression _if(Executor e, IList<Expression> args) {
bool test = ((Compiler.Boolean) e.eval(args[0])).value;
bool test = e.eval(args[0]) != (new Compiler.Boolean(false));
return e.eval(args[1 + (test ? 0 : 1)]);
}
private static Expression _define(Executor e, IList<Expression> args) {
@ -251,6 +260,22 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
Compiler.List other_args = (Compiler.List) args[1];
return e.EvalFunction(arg0, other_args.expressions);
}
private static Expression _and(Executor e, IList<Expression> args) {
Expression result = new Compiler.Boolean(false);
foreach (var exp in args) {
result = e.eval(exp);
if (result == new Compiler.Boolean(false)) { return result; }
}
return result;
}
private static Expression _or(Executor e, IList<Expression> args) {
Expression result = new Compiler.Boolean(false);
foreach (var exp in args) {
result = e.eval(exp);
if (result != new Compiler.Boolean(false)) { return result; }
}
return result;
}
}
public class Executor {

View file

@ -110,7 +110,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
_logger.LogDebug("Item {0} evaluated to {1}", i, r.ToString());
if (r is Lisp_Boolean r_bool) {
if (r_bool.value) {
_logger.LogDebug("Added "{0}" to Smart Playlist {1}", i, smartPlaylist.Name);
_logger.LogDebug("Added '{0}' to Smart Playlist {1}", i, smartPlaylist.Name);
results.Add(i.Id);
}
} else {

View file

@ -21,7 +21,7 @@ namespace Tests
public class Test {
[Fact]
public static void TestTokenizer() {
StringTokenStream sts = StringTokenStream.generate("(\"some literal string\" def ghj +100 -+300 1 ++ !=)");
StringTokenStream sts = StringTokenStream.generate("(\"some literal string\" def ghj +100 -+300 1 >= ++ !=)");
Assert.Equal(sts.get().value, "(");
Assert.Equal(sts.get().value, "\"");
Assert.Equal(sts.get().value, "some");
@ -44,9 +44,14 @@ namespace Tests
Assert.Equal(sts.get().value, " ");
Assert.Equal(sts.get().value, "1");
Assert.Equal(sts.get().value, " ");
Assert.Equal(sts.get().value, "++");
Assert.Equal(sts.get().value, ">");
Assert.Equal(sts.get().value, "=");
Assert.Equal(sts.get().value, " ");
Assert.Equal(sts.get().value, "!=");
Assert.Equal(sts.get().value, "+");
Assert.Equal(sts.get().value, "+");
Assert.Equal(sts.get().value, " ");
Assert.Equal(sts.get().value, "!");
Assert.Equal(sts.get().value, "=");
Assert.Equal(sts.get().value, ")");
sts.commit();
Assert.Equal(sts.available(), 0);
@ -87,16 +92,22 @@ namespace Tests
Assert.Equal(((Integer) e).value, 10);
e = new Executor().eval("(cdr (10 20 30))");
Assert.Equal(string.Format("{0}", e), "( 20 30)");
Assert.Equal(string.Format("{0}", e), "(20 30)");
e = new Executor().eval("(cons 1 3)");
Assert.Equal(string.Format("{0}", e), "( 1 3)");
Assert.Equal(string.Format("{0}", e), "(1 3)");
e = new Executor().eval("(cons 1 (2 3))");
Assert.Equal(string.Format("{0}", e), "( 1 2 3)");
Assert.Equal(string.Format("{0}", e), "(1 2 3)");
e = new Executor().eval("(length (cons 1 (2 3)))");
Assert.Equal(string.Format("{0}", e), "3");
e = new Executor().eval("(>= 2 2)");
Assert.Equal(string.Format("{0}", e), "t");
e = new Executor().eval("(> 2 2))");
Assert.Equal(string.Format("{0}", e), "nil");
}
[Fact]
public static void ObjectTest() {
@ -106,7 +117,7 @@ namespace Tests
r = e.eval("(haskeys o 'i' 'b')");
Assert.Equal(((Lisp_Boolean)r).value, true);
r = e.eval("(getitems o 'i' 'b')");
Assert.Equal(string.Format("{0}", r), "( 5 nil)");
Assert.Equal(string.Format("{0}", r), "(5 nil)");
}
}
}