fix: parsing of multi-character operators and tests.
This commit is contained in:
parent
1be3b17bae
commit
eb45ed5772
4 changed files with 60 additions and 10 deletions
|
@ -276,7 +276,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
|
||||||
case AtomToken at:
|
case AtomToken at:
|
||||||
return parse_atom(at);
|
return parse_atom(at);
|
||||||
case OperatorToken ot:
|
case OperatorToken ot:
|
||||||
return new Symbol(ot.value);
|
return parse_operator(ot);
|
||||||
case SpaceToken sp:
|
case SpaceToken sp:
|
||||||
return parse();
|
return parse();
|
||||||
}
|
}
|
||||||
|
@ -330,5 +330,19 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
|
||||||
_sts.commit();
|
_sts.commit();
|
||||||
return new Symbol(at.value);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
|
||||||
this["car"] = _car;
|
this["car"] = _car;
|
||||||
this["cdr"] = _cdr;
|
this["cdr"] = _cdr;
|
||||||
this["cons"] = _cons;
|
this["cons"] = _cons;
|
||||||
|
this["not"] = _not;
|
||||||
this["length"] = _length;
|
this["length"] = _length;
|
||||||
this["haskeys"] = _haskeys;
|
this["haskeys"] = _haskeys;
|
||||||
this["getitems"] = _getitems;
|
this["getitems"] = _getitems;
|
||||||
|
@ -170,6 +171,12 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
|
||||||
}
|
}
|
||||||
throw new ApplicationException();
|
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) {
|
private static Expression _length(IList<Expression> args) {
|
||||||
return new Integer(((Compiler.List)args[0]).expressions.Count());
|
return new Integer(((Compiler.List)args[0]).expressions.Count());
|
||||||
}
|
}
|
||||||
|
@ -231,9 +238,11 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
|
||||||
this["if"] = _if;
|
this["if"] = _if;
|
||||||
this["define"] = _define;
|
this["define"] = _define;
|
||||||
this["apply"] = _apply;
|
this["apply"] = _apply;
|
||||||
|
this["and"] = _and;
|
||||||
|
this["or"] = _or;
|
||||||
}
|
}
|
||||||
private static Expression _if(Executor e, IList<Expression> args) {
|
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)]);
|
return e.eval(args[1 + (test ? 0 : 1)]);
|
||||||
}
|
}
|
||||||
private static Expression _define(Executor e, IList<Expression> args) {
|
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];
|
Compiler.List other_args = (Compiler.List) args[1];
|
||||||
return e.EvalFunction(arg0, other_args.expressions);
|
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 {
|
public class Executor {
|
||||||
|
|
|
@ -110,7 +110,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.ScheduledTasks {
|
||||||
_logger.LogDebug("Item {0} evaluated to {1}", i, r.ToString());
|
_logger.LogDebug("Item {0} evaluated to {1}", i, r.ToString());
|
||||||
if (r is Lisp_Boolean r_bool) {
|
if (r is Lisp_Boolean r_bool) {
|
||||||
if (r_bool.value) {
|
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);
|
results.Add(i.Id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace Tests
|
||||||
public class Test {
|
public class Test {
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void TestTokenizer() {
|
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, "\"");
|
Assert.Equal(sts.get().value, "\"");
|
||||||
Assert.Equal(sts.get().value, "some");
|
Assert.Equal(sts.get().value, "some");
|
||||||
|
@ -44,9 +44,14 @@ namespace Tests
|
||||||
Assert.Equal(sts.get().value, " ");
|
Assert.Equal(sts.get().value, " ");
|
||||||
Assert.Equal(sts.get().value, "1");
|
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, "!");
|
||||||
|
Assert.Equal(sts.get().value, "=");
|
||||||
Assert.Equal(sts.get().value, ")");
|
Assert.Equal(sts.get().value, ")");
|
||||||
sts.commit();
|
sts.commit();
|
||||||
Assert.Equal(sts.available(), 0);
|
Assert.Equal(sts.available(), 0);
|
||||||
|
@ -87,16 +92,22 @@ namespace Tests
|
||||||
Assert.Equal(((Integer) e).value, 10);
|
Assert.Equal(((Integer) e).value, 10);
|
||||||
|
|
||||||
e = new Executor().eval("(cdr (10 20 30))");
|
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)");
|
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))");
|
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)))");
|
e = new Executor().eval("(length (cons 1 (2 3)))");
|
||||||
Assert.Equal(string.Format("{0}", e), "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]
|
[Fact]
|
||||||
public static void ObjectTest() {
|
public static void ObjectTest() {
|
||||||
|
@ -106,7 +117,7 @@ namespace Tests
|
||||||
r = e.eval("(haskeys o 'i' 'b')");
|
r = e.eval("(haskeys o 'i' 'b')");
|
||||||
Assert.Equal(((Lisp_Boolean)r).value, true);
|
Assert.Equal(((Lisp_Boolean)r).value, true);
|
||||||
r = e.eval("(getitems o 'i' 'b')");
|
r = e.eval("(getitems o 'i' 'b')");
|
||||||
Assert.Equal(string.Format("{0}", r), "( 5 nil)");
|
Assert.Equal(string.Format("{0}", r), "(5 nil)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue